<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-992119016619597159</id><updated>2025-07-03T07:16:22.285+02:00</updated><category term="Ext"/><category term="Ext.Учебник.Таблицы PHP SQL"/><category term="App Engine"/><category term="Chrome Extension dev"/><category term="Ext.Учебник.Расширение Ext для новичков"/><category term="Ext.Учебник.Создание приложений в ExtJS"/><category term="Google"/><category term="Google App Script"/><category term="Kubernetes"/><category term="html 5"/><category term="jQuery"/><category term="Мои записки"/><category term="Учебник: работа с данными в Ext"/><title type='text'>JavaScript: React, NodeJS,  jQuery, Ext и т.д. + html 5 + Google App Engine</title><subtitle type='html'>мой блог по JavaScript, React, NodeJS, jQuery, Ext и подобным,html5 and etc.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-6952975992384879790</id><published>2024-11-04T22:02:00.004+02:00</published><updated>2024-11-04T22:02:49.501+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kubernetes"/><title type='text'> Динамическое предоставление томов в Kubernetes</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Динамическое предоставление томов дает возможность создания томов по требованию. Без динамического представления админисраторы кластера должны вручную обращаться к своим облачным хранилищам или службам хранения данных для создания новых томов, а затем создавать объекты персистентных томов PersistentVolume для представления этих хранилищ в Kubernetes. Функция динамического представления убирает необходимость предварительной подготовки хранилища администраторами кластера. Вместо этого, она автоматически представляет хранилище, когда пользователь создает объекты PersistentVolumeClaim.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;Общая информация&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Реализация динамического предоставления томов основана на объекте класса хранилища (StorageClass) в API, который находится в API группе storage.k8s.io. Администратор кластера может определить необходимое количество обьектов классов хранилища, в каждом их которых указывается плагин для тома (aka представитель), который предоставляет том и набор параметров для передачи представителю при предоставлении. Администратор кластера может определить и представить множество разновидностей хранилищ (от одной или разных систем хранения данных) в кластере, каждый с собственным набором параметров. Этот подход также избавляет конечного пользователя от сложностей и нюансов процесса выделения хранилища, но все еще дает возможность выбора из множества возможных хранилищ.&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Дополнительную информацию о классах хранилищ можно найти по адресу: &lt;a href=&quot;https://kubernetes.io/docs/concepts/storage/storage-classes/&quot;&gt;https://kubernetes.io/docs/concepts/storage/storage-classes/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;Включение динамического предоставления&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Чтобы включить динамическое предоставление, админисратору кластера нужно предварительно создать один или более объектов StorageClass для пользователей. Объекты StorageClass определяют какой надо использовать плагин преддоставления и какие параметры следует ему передавать когда будет вызвано динамическое предоставление. Имя объекта StorageClass должно быть валидным DNS именем субдомена.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Следующий манифест создает класс хранилища &quot;slow&quot; который предоставляет персистентные диски, похожие на стандартные.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;apiVersion: storage.k8s.io/v1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;kind: StorageClass&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;metadata:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; name: slow&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;provisioner: kubernetes.io/gce-pd&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;parameters:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; type: pd-standard&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Следующий манифест создает класс хранилища &quot;fast&quot; который предоставляет персистентные диски, похожие на SSD.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;apiVersion: storage.k8s.io/v1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;kind: StorageClass&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;metadata:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; name: fast&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;provisioner: kubernetes.io/gce-pd&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;parameters:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; type: pd-ssd&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;Использование динамического предоставления&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Пользователи запрашивают динамически-предоставляемые хранилища включая класс хранилища в свои манифесты PersistentVolumeClaim. До версии Kubernetes v1.6 это делалось через аннотацию volume.beta.kubernetes.io/storage-class. Однако, эта аннотация стала устаревшей с версии 1.9. Пользователи теперь могут и должны вместо этого использовать поле storageClassName объекта PersistentVolumeClaim. Значение этого поля должно совпадать с именем класса хранилища StorageClass, сконфигурированного администратором (смотри далее).&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Чтобы выбрать класс хранилища &quot;fast&quot;, пользователь должен был бы создать следующий PersistentVolumeClaim:&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;apiVersion: v1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;kind: PersistentVolumeClaim&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;metadata:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; name: claim1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;spec:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; accessModes:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; &amp;nbsp; - ReadWriteOnce&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; storageClassName: fast&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; resources:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; &amp;nbsp; requests:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;background-color: #fcff01;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; storage: 30Gi&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Это требование повлечет автоматическое предоставление персистентного диска типа SSD. При удалении требования, том также будет удален.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;Поведение по умолчанию&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Может быть выставлено такое динамическое предоставление в кластере, что если не указан класс хранилища, то они все считаются динамическими. Администратор кластера может включить это поведение так:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;Пометить один объект класса хранилищ по умолчанию;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;Убедиться, что контроллер допуска DefaultStorageClass включен в API сервере.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Администратор может пометить конкретный StorageClass по умолчанию, добавив ему аннотацию storageclass.kubernetes.io/is-default-class. Когда в кластере существует класс хранилища по умолчанию и пользователь создает PersistentVolumeClaim, в котором не указан storageClassName, то контроллер допуска DefaultStorageClass автоматически добавляет поле storageClassName, которое указывает на класс по умолчанию.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Если создать более одного класса хранилищ по умолчанию в кластере, то в таком случае будет использоваться самый последний класс, назначенный классом по умолчанию.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;В мульти-зональных кластерах Поды могут быть распределены по зонам в регионе. Однозональные сервисы хранения данных должны в этом случае присутствовать на всех зонах, где будут эти Поды. Это можно настроить установкой режима монтирования томов Volume Binding Mode.&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Источник перевода:&amp;nbsp;https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/6952975992384879790/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2024/11/kubernetes.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6952975992384879790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6952975992384879790'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2024/11/kubernetes.html' title=' Динамическое предоставление томов в Kubernetes'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-8527810738028426878</id><published>2022-02-15T09:28:00.005+02:00</published><updated>2023-02-25T07:24:01.582+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Chrome Extension dev"/><title type='text'>Как сделать простое расширение для Chrome. Простой пример из документации. Перевод (вольный).</title><content type='html'>&lt;p&gt;Расширения - набор файлов, содержащих отдельные, но работающие совместно компоненты.&lt;/p&gt;&lt;p&gt;Эти компоненты могут быть фоновыми скриптами, контентными скриптами, страницами настроек, элементами пользовательского интерфейса и различными файлами с логикой. Для создания этих компонентов используются технологии интернет-разработки: HTML, CSS и JavaScript. Компоненты расширения могут выполнять различные функции и ни один компонент не является обязательным.&lt;/p&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;В этом примере мы создадим расширение, которое позволит пользователю менять цвет фона текущей просматриваемой в браузере страницы. Расширение будет использовать несколько компонентов платформы расширений, чтобы дать представление для начала работы с ними и связями между ними.&lt;/p&gt;&lt;p&gt;Для начала, создадим директорию, где будут находиться файлы расширения.&lt;/p&gt;&lt;p&gt;Создайте файл манифеста.&lt;/p&gt;&lt;p&gt;Работа расширения начинается с его манифеста. Создайте файл с именем manifest.json и скопируйте в него следующий код:&lt;/p&gt;&lt;p&gt;{&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;name&quot;: &quot;Getting Started Example&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;description&quot;: &quot;Build an Extension!&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;version&quot;: &quot;1.0&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;manifest_version&quot;: 3&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Фактически мы уже создали расширение, которое можем загрузить в браузер. Директория, содержащая файл манифеста может быть добавлена как расширение в режиме разработчика. Для этого:&lt;/p&gt;&lt;p&gt;Откройте страницу управления расширениями chrome://extensions. Можно также найти ее через пункт в меню &quot;Дополнительные инструменты - Расширения&quot;.&lt;/p&gt;&lt;p&gt;Включите режим разработчика с помощью переключателя справа.&lt;/p&gt;&lt;p&gt;Нажмите кнопку &quot;Загрузить распакованное расширение&quot; и выберите директорию с нашим расширением.&lt;/p&gt;&lt;p&gt;Вот и все! Расширение успешно установлено и мы можем видеть далее результаты нашей разработки. Мы пока еще не включили в манифест собственные иконки для отображения, поэтому браузер использовал стандартные.&lt;/p&gt;&lt;p&gt;Добавляем функциональность&lt;/p&gt;&lt;p&gt;Итак, расширение установлено, но оно пока ничего не делает, так как пока у нас есть только файл манифеста и все. Давайте исправим это и добавим немного кода для хранения значения цвета, который мы будем использовать для покраски фона открытой страницы.&lt;/p&gt;&lt;p&gt;Регистрация фонового скрипта в манифесте.&lt;/p&gt;&lt;p&gt;Фоновые скрипты, как многие другие важные компоненты расширения, должны быть зарегистрированы в манифесте. Это своего рода реестр ресурсов, которые может использовать расширение. Регистрация фонового скрипта в манифесте сообщит расширению ссылку на файл и как этот файл надо обрабатывать.&lt;/p&gt;&lt;p&gt;{&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;name&quot;: &quot;Getting Started Example&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;description&quot;: &quot;Build an Extension!&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;version&quot;: &quot;1.0&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;manifest_version&quot;: 3,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;background&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;service_worker&quot;: &quot;background.js&quot;&lt;/p&gt;&lt;p&gt;&amp;nbsp; }&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;Теперь Chrome знает, что расширение имеет сервисный обработчик (фоновый скрипт). Когда вы перезагрузите расширение, Chrome обнаружит указанные дополнительные инструкции, такие как важные события, которые необходимо отслеживать, например.&lt;/p&gt;&lt;p&gt;Создадим фоновый скрипт&lt;/p&gt;&lt;p&gt;Этому расширению необходимо получать информацию из какой то постоянной переменной после того как расширение будет установлено. Начнем с отслеживания события установки расширения runtime.onInstalled в фоновом скрипте. Внутри обработчика onInstalled расширение создаст и установит значение переменной в хранилище Storage API, используемом браузером для хранения информации. Это даст возможность нескольким компонентам расширения получать эту информацию и обновлять ее. В папке расширения создадим файл background.js и добавим следующий код:&lt;/p&gt;&lt;p&gt;// background.js&lt;/p&gt;&lt;p&gt;let color = &#39;#3aa757&#39;;&lt;/p&gt;&lt;p&gt;chrome.runtime.onInstalled.addListener(() =&amp;gt; {&lt;/p&gt;&lt;p&gt;&amp;nbsp; chrome.storage.sync.set({ color });&lt;/p&gt;&lt;p&gt;&amp;nbsp; console.log(&#39;Default background color set to %cgreen&#39;, `color: ${color}`);&lt;/p&gt;&lt;p&gt;});&lt;/p&gt;&lt;p&gt;Этот код просто записывает в хранилище расширения значение переменной color в момент установки расширения и выводит сообщение об этом в консоль страницы фонового скрипта расширения.&lt;/p&gt;&lt;p&gt;Добавление разрешения на работу с хранилищем&lt;/p&gt;&lt;p&gt;Большинство API, включая и API для работы с хранилищем, должны быть зарегистрированы в поле &quot;permissions&quot; в манифесте, чтобы расширение могло использовать эти API.&lt;/p&gt;&lt;p&gt;{&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;name&quot;: &quot;Getting Started Example&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;description&quot;: &quot;Build an Extension!&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;version&quot;: &quot;1.0&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;manifest_version&quot;: 3,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;background&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;service_worker&quot;: &quot;background.js&quot;&lt;/p&gt;&lt;p&gt;&amp;nbsp; },&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;permissions&quot;: [&quot;storage&quot;]&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;Просмотр фонового скрипта в браузере.&lt;/p&gt;&lt;p&gt;Откройте страницу управления расширением и кликните на ссылку перезагрузки с круговой стрелкой. Появится новое поле Отладка страниц с синей ссылкой service worker.&lt;/p&gt;&lt;p&gt;Кликнем на эту ссылку и увидим вывод в консоли от фонового скрипта, &quot;Default background color set to green&quot;.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Пользовательский интерфейс расширения.&lt;/p&gt;&lt;p&gt;Расширения могут иметь множество вариантов интерфейса пользователя; в нашем примере мы будем использовать popup - всплывающее окно. Создадим в папке расширения файл popup.html. Наше расширение будет использовать кнопку для изменения фонового цвета страницы. Вот код:&lt;/p&gt;&lt;p&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;lt;html&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;head&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;button.css&quot;&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;/head&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;body&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;button id=&quot;changeColor&quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;/body&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;lt;/html&amp;gt;&lt;/p&gt;&lt;p&gt;Как и в случае с фоновым скриптом, этот файл тоже должен быть объявлен в манифесте, чтобы указать браузеру Chrome, что он будет использоваться для вывода всплывающего окна расширения. Чтобы это сделать добавим поле action в манифест и установим в нем свойству default_popup значение с именем нашего скрипта popup.html.&lt;/p&gt;&lt;p&gt;{&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;name&quot;: &quot;Getting Started Example&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;description&quot;: &quot;Build an Extension!&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;version&quot;: &quot;1.0&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;manifest_version&quot;: 3,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;background&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;service_worker&quot;: &quot;background.js&quot;&lt;/p&gt;&lt;p&gt;&amp;nbsp; },&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;permissions&quot;: [&quot;storage&quot;],&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;action&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;default_popup&quot;: &quot;popup.html&quot;&lt;/p&gt;&lt;p&gt;&amp;nbsp; }&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;В нашем файле есть ссылка на внешнюю таблицу стилей button.css. Давайте напишем ее. Создадим файл button.css и добавим код:&lt;/p&gt;&lt;p&gt;button {&lt;/p&gt;&lt;p&gt;&amp;nbsp; height: 30px;&lt;/p&gt;&lt;p&gt;&amp;nbsp; width: 30px;&lt;/p&gt;&lt;p&gt;&amp;nbsp; outline: none;&lt;/p&gt;&lt;p&gt;&amp;nbsp; margin: 10px;&lt;/p&gt;&lt;p&gt;&amp;nbsp; border: none;&lt;/p&gt;&lt;p&gt;&amp;nbsp; border-radius: 2px;&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;button.current {&lt;/p&gt;&lt;p&gt;&amp;nbsp; box-shadow: 0 0 0 2px white,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0 0 0 4px black;&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;Также добавим иконки панели инструментов в поле default_icons. Вы можете скачать их &lt;a href=&quot;https://storage.googleapis.com/web-dev-uploads/file/WlD8wC6g8khYWPJUsQceQkhXSlv1/wy3lvPQdeJn4iqHmI0Rp.zip&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;здесь&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Распакуйте их и поместите в папку расширения. Обновим манифест, чтобы браузер узнал о них.&lt;/p&gt;&lt;p&gt;{&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;name&quot;: &quot;Getting Started Example&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;description&quot;: &quot;Build an Extension!&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;version&quot;: &quot;1.0&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;manifest_version&quot;: 3,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;background&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;service_worker&quot;: &quot;background.js&quot;&lt;/p&gt;&lt;p&gt;&amp;nbsp; },&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;permissions&quot;: [&quot;storage&quot;],&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;action&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;default_popup&quot;: &quot;popup.html&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;default_icon&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;16&quot;: &quot;/images/get_started16.png&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;32&quot;: &quot;/images/get_started32.png&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;48&quot;: &quot;/images/get_started48.png&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;128&quot;: &quot;/images/get_started128.png&quot;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;p&gt;&amp;nbsp; }&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;Расширение также показывает изображения на странице управления расширения, предупреждений о разрешениях от пользователя и избранном. Эти изображения-иконки также указываются в манифесте при необходимости:&lt;/p&gt;&lt;p&gt;{&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;name&quot;: &quot;Getting Started Example&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;description&quot;: &quot;Build an Extension!&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;version&quot;: &quot;1.0&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;manifest_version&quot;: 3,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;background&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;service_worker&quot;: &quot;background.js&quot;&lt;/p&gt;&lt;p&gt;&amp;nbsp; },&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;permissions&quot;: [&quot;storage&quot;],&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;action&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;default_popup&quot;: &quot;popup.html&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;default_icon&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;16&quot;: &quot;/images/get_started16.png&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;32&quot;: &quot;/images/get_started32.png&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;48&quot;: &quot;/images/get_started48.png&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;128&quot;: &quot;/images/get_started128.png&quot;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;p&gt;&amp;nbsp; },&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;icons&quot;: {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;16&quot;: &quot;/images/get_started16.png&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;32&quot;: &quot;/images/get_started32.png&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;48&quot;: &quot;/images/get_started48.png&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &quot;128&quot;: &quot;/images/get_started128.png&quot;&lt;/p&gt;&lt;p&gt;&amp;nbsp; }&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;По-умолчанию, расширения появляются в меню расширений. Если его закрепить, то появится иконка расширения прямо на панели инструментов браузера.&lt;/p&gt;&lt;p&gt;Если на этом этапе перезагрузить расширение, оно будет включать уже свою иконку вместо иконки, подставляемых по-умолчанию при отсутствии собственных иконок. Если мы кликнем на эту иконку расширения в панели инструментов, то откроется небольшое всплывающее окошко, показывающее цвет, используемый для покраски фона страницы, который будет по-умолчанию.&lt;/p&gt;&lt;p&gt;Последний шаг для интерфейса этого окна это изменение цвета кнопки. Создадим для этого скрипт popup.js со следующим кодом и также добавим его в папку расширения:&lt;/p&gt;&lt;p&gt;// Инициализируем кнопку предпочитаемым пользователем цветом&lt;/p&gt;&lt;p&gt;let changeColor = document.getElementById(&quot;changeColor&quot;);&lt;/p&gt;&lt;p&gt;chrome.storage.sync.get(&quot;color&quot;, ({ color }) =&amp;gt; {&lt;/p&gt;&lt;p&gt;&amp;nbsp; changeColor.style.backgroundColor = color;&lt;/p&gt;&lt;p&gt;});&lt;/p&gt;&lt;p&gt;Этот код получает элемент кнопки из файла popup.html и запрашивает значение цвета из хранилища. Затем он применяет этот цвет в качестве фонового для самой кнопки. Подключим этот скрипт к странице popup.html.&lt;/p&gt;&lt;p&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;lt;html&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;head&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;button.css&quot;&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;/head&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;body&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;button id=&quot;changeColor&quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;script src=&quot;popup.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;/body&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;lt;/html&amp;gt;&lt;/p&gt;&lt;p&gt;Перезагрузим расширение, чтобы увидеть зеленую кнопку при клике на кнопку расширения в панели браузера.&lt;/p&gt;&lt;p&gt;Логика слоев&lt;/p&gt;&lt;p&gt;Теперь у расширения есть собственная иконка и всплывающее окно свойств с кнопкой и оно меняет фоновый цвет кнопки на то значение, которое записано в хранилище расширения (мы изначально записали это значение при установке расширения в фоновом скрипте). Дальше нам нужно логика для взаимодействия с пользователем. Обновим код popup.js, добавим строки в конец файла:&lt;/p&gt;&lt;p&gt;// При нажатии кнопки, инжектируем функцию setPageBackgroundColor в код текущей просматриваемой страницы в браузере.&lt;/p&gt;&lt;p&gt;changeColor.addEventListener(&quot;click&quot;, async () =&amp;gt; {&lt;/p&gt;&lt;p&gt;&amp;nbsp; let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; chrome.scripting.executeScript({&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; target: { tabId: tab.id },&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; function: setPageBackgroundColor,&lt;/p&gt;&lt;p&gt;&amp;nbsp; });&lt;/p&gt;&lt;p&gt;});&lt;/p&gt;&lt;p&gt;// Эта функция выполнится как контентный скрипт внутри текущей открытой страницы&lt;/p&gt;&lt;p&gt;function setPageBackgroundColor() {&lt;/p&gt;&lt;p&gt;&amp;nbsp; chrome.storage.sync.get(&quot;color&quot;, ({ color }) =&amp;gt; {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; document.body.style.backgroundColor = color;&lt;/p&gt;&lt;p&gt;&amp;nbsp; });&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;Теперь обновленный код добавляем обработчик нажатия кнопки, который запускает функцию как контентный скрипт. Этот код присваивает цвету страницы значение фонового цвета кнопки расширения, а точнее значение, записанное в хранилище расширения для этой кнопки. Использование программной инжекции позволяет использовать вызываемые пользователем контентные скрипты вместо авто-вставки ненужного кода в сами вэб-страницы.&lt;/p&gt;&lt;p&gt;Нам понадобится добавить разрешение activeTab, чтобы позволить расширению доступ к текущей странице и скриптовое расширение для использования метода executeScript из Scripting API. Добавим их:&lt;/p&gt;&lt;p&gt;{&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;name&quot;: &quot;Getting Started Example&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; ...&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;permissions&quot;: [&quot;storage&quot;, &quot;activeTab&quot;, &quot;scripting&quot;],&lt;/p&gt;&lt;p&gt;&amp;nbsp; ...&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;Теперь расширение полностью функционально. Перезагрузите его, обновите страницу, откройте всплывающее окно расширения и нажмите кнопку, чтобы перекрасить фон страницы в зеленый. Однако, некоторые пользователи захотят изменить этот фоновый цвет на другой.&lt;/p&gt;&lt;p&gt;Важная заметка!&lt;/p&gt;&lt;p&gt;Расширения не могут инжектировать контентные скрипты на внутренние страницы Chrome, такие как &quot;chrome://extensions&quot; и т.п. Тестируйте его на реальных интернет-сайтах, вроде https://google.com.&lt;/p&gt;&lt;p&gt;Дадим пользователю настройки расширения&lt;/p&gt;&lt;p&gt;На данный момент расширение позволяет изменять фоновый цвет страницы только на зеленый цвет. Подключение страницы настроек дает пользователям больше контроля над функциональностью расширения, а значит и браузера в целом.&lt;/p&gt;&lt;p&gt;Начните с создания в папке расширения файла options.html со следующим кодом.&lt;/p&gt;&lt;p&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;lt;html&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;head&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;button.css&quot;&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;/head&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;body&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;div id=&quot;buttonDiv&quot;&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;div&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;p&amp;gt;Choose a different background color!&amp;lt;/p&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;/body&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;script src=&quot;options.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;lt;/html&amp;gt;&lt;/p&gt;&lt;p&gt;Теперь зарегистрируем эту страницу настроек в манифесте:&lt;/p&gt;&lt;p&gt;{&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;name&quot;: &quot;Getting Started Example&quot;,&lt;/p&gt;&lt;p&gt;&amp;nbsp; ...&lt;/p&gt;&lt;p&gt;&amp;nbsp; &quot;options_page&quot;: &quot;options.html&quot;&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;Перезагрузим расширение и кликнем на иконке расширения в панели браузера правой кнопкой мыши и выберем пункт Параметры.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Последний шаг это добавить логику параметров. Создадим файл с именем options.js в папке расширения и добавим в него код:&lt;/p&gt;&lt;p&gt;let page = document.getElementById(&quot;buttonDiv&quot;);&lt;/p&gt;&lt;p&gt;let selectedClassName = &quot;current&quot;;&lt;/p&gt;&lt;p&gt;const presetButtonColors = [&quot;#3aa757&quot;, &quot;#e8453c&quot;, &quot;#f9bb2d&quot;, &quot;#4688f1&quot;];&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;// обработаем нажатие кнопки окрасив выбранную кнопку и сохраняя выбор&lt;/p&gt;&lt;p&gt;function handleButtonClick(event) {&lt;/p&gt;&lt;p&gt;&amp;nbsp; // Удалим стиль предыдущего выбранного цвета&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp; let current = event.target.parentElement.querySelector(&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; `.${selectedClassName}`&lt;/p&gt;&lt;p&gt;&amp;nbsp; );&lt;/p&gt;&lt;p&gt;&amp;nbsp; if (current &amp;amp;&amp;amp; current !== event.target) {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; current.classList.remove(selectedClassName);&lt;/p&gt;&lt;p&gt;&amp;nbsp; }&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; // Пометим кнопку как выбранную&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp; let color = event.target.dataset.color;&lt;/p&gt;&lt;p&gt;&amp;nbsp; event.target.classList.add(selectedClassName);&lt;/p&gt;&lt;p&gt;&amp;nbsp; chrome.storage.sync.set({ color });&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;// Добавим кнопку на страницу для каждого предоставляемого цвета&lt;/p&gt;&lt;p&gt;function constructOptions(buttonColors) {&lt;/p&gt;&lt;p&gt;&amp;nbsp; chrome.storage.sync.get(&quot;color&quot;, (data) =&amp;gt; {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; let currentColor = data.color;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; // для каждого цвета мы ...&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; for (let buttonColor of buttonColors) {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; // ... создаем кнопку этого цвета&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; let button = document.createElement(&quot;button&quot;);&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; button.dataset.color = buttonColor;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; button.style.backgroundColor = buttonColor;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; // …отмечает кнопку выбранного цвета…&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; if (buttonColor === currentColor) {&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; button.classList.add(selectedClassName);&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; // … и регистрируем обработчик нажатия кнопки&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; button.addEventListener(&quot;click&quot;, handleButtonClick);&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; page.appendChild(button);&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;p&gt;&amp;nbsp; });&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;// Инициализируем страницу, соберем настройки цвета&lt;/p&gt;&lt;p&gt;constructOptions(presetButtonColors);&lt;/p&gt;&lt;p&gt;На странице настроек будем представлено четыре кнопки с цветами и обработчиками событий. Когда пользователь нажимает на кнопку, она обновляет значение цвета в хранилище расширения. Так как все файлы расширения получают информацию об этом цвете из этого хранилища, больше ничего обновлять не требуется.&lt;/p&gt;&lt;p&gt;На этом простой пример создания расширения завершен.&lt;/p&gt;&lt;p&gt;Эта страница является переводом&amp;nbsp;https://developer.chrome.com/docs/extensions/mv3/getstarted/ с небольшими отступлениями от точного текста.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/8527810738028426878/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2022/02/chrome-extensions.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/8527810738028426878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/8527810738028426878'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2022/02/chrome-extensions.html' title='Как сделать простое расширение для Chrome. Простой пример из документации. Перевод (вольный).'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-8972495520797383275</id><published>2015-03-23T08:11:00.000+02:00</published><updated>2015-03-23T08:11:54.627+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Google App Script"/><title type='text'>Кратко о Google Apps Script</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUD7NfrqeRw7-sBYCua9qzPbDnQpw3XTC4VvzRNqIedH-GOQABY4Q1oAbXbPDuYSJBQP_uMBAkQQ04i5SWG8aIA3MTP-mKtinAwPY7UJTouWQHeAIuS78CRZQZFW6OYAswiuHLE3_kRJQ/s1600/google-script.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUD7NfrqeRw7-sBYCua9qzPbDnQpw3XTC4VvzRNqIedH-GOQABY4Q1oAbXbPDuYSJBQP_uMBAkQQ04i5SWG8aIA3MTP-mKtinAwPY7UJTouWQHeAIuS78CRZQZFW6OYAswiuHLE3_kRJQ/s1600/google-script.png&quot; height=&quot;197&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Google App Script - это язык скриптов, основанный на JavaScript, с помощью которого вы можете разработать или добавить новый функционал для таких приложений Google, как Google Docs, Sheets и Forms.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Не надо ничего устанавливать на компьютер, чтобы начать работать с этим языком. Вы используете браузер для работы в редакторе, а код запускается прямо на серверах Google.&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;/div&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Apps Script достаточно универсален. Вот некоторые функции, которые вы можете создать с его помощью:&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
- добавить собственные меню, диалоговые окна или панели в документах Google Docs, Sheets или Forms.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
- создавать собственные функции для Google Sheets&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
- создавать приложения web apps и публиковать их как самостоятельные или встраиваемые в Google Sites&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
- взаимодействовать с другими сервисами Google: Adsense, Analytics, Calendar, Drive, Gmail и Maps.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Чтобы посмотреть работу App Script в действии, посмотрите 5-минутные быстрые примеры:&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;a href=&quot;https://developers.google.com/apps-script/quickstart/macros&quot; target=&quot;_blank&quot;&gt;Макросы, меню и собственные функции&lt;/a&gt; - улучшите ваши Google Sheets с помощью дополнительных функций и создавайте собственные отчеты на основе таблиц.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;a href=&quot;https://developers.google.com/apps-script/quickstart/forms&quot; target=&quot;_blank&quot;&gt;Управляйте ответами на формы Google Forms&lt;/a&gt; - уведомляет через службу календаря всех пользователей, заполнивших форму.&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Продолжение следует...&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/8972495520797383275/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2015/03/google-apps-script.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/8972495520797383275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/8972495520797383275'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2015/03/google-apps-script.html' title='Кратко о Google Apps Script'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUD7NfrqeRw7-sBYCua9qzPbDnQpw3XTC4VvzRNqIedH-GOQABY4Q1oAbXbPDuYSJBQP_uMBAkQQ04i5SWG8aIA3MTP-mKtinAwPY7UJTouWQHeAIuS78CRZQZFW6OYAswiuHLE3_kRJQ/s72-c/google-script.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-8806708021540779205</id><published>2014-04-03T15:15:00.002+03:00</published><updated>2023-02-25T07:24:35.183+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="App Engine"/><title type='text'>Google App Engine - система авторизации и аутентификации пользователей. Регулируем и экономим.</title><content type='html'>Еще раз возвращаюсь к Google App Engine и обдумыванию реализации авторизации и аутентификации пользователей на сайте.&lt;br /&gt;
Конечно, можно предположить, что все наши посетители - пользователи Google и на этом сильно сэкономить :), однако предположим, что большинство из них не обладает учеткой Google, либо не хочет светить ее и акцептировать наш сайт.&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;
Возьмем все труды по ведению базы пользователей на себя.&lt;br /&gt;
При традиционной реализации, с учетом, что надо сделать надежную систему, накладные ресурсы будут расти как на дрожжах.&lt;br /&gt;
А потому введем некоторые ограничения.&lt;br /&gt;
Система будет работать на основе сессий. Сессия будет генерироваться и записываться в кукис браузера пользователя только после прохождения аутентификации на сайте.&lt;br /&gt;
Этот момент уже убирает нагрузку по работе с БД. Ну, точнее расходы, связанные с операциями с БД.&lt;br /&gt;
Кукис с сессией должен иметь разумный срок хранения в пределах суток - устанавливая его длительность можем регулировать &quot;расходы&quot;.&lt;br /&gt;
Кукис должны удаляться принудительно только при выходе из системы самим пользователем или автоматически при истечении срока хранения (скажем - сутки).&lt;br /&gt;
Далее..&lt;br /&gt;
Допустим, пользователь залогинился, походил и отошел.. кукис еще в браузере.&lt;br /&gt;
При заходе на сайт имеем ситуацию - пускать его автоматом в &quot;кабинет&quot; или заставлять логиниться?&lt;br /&gt;
Тут мы должны определиться для себя на сервере - незакрытые сессии мы храним, ну или считаем активными в течение допустим суток!&lt;br /&gt;
Какие накладные &quot;расходы&quot; в этом случае?&lt;br /&gt;
Мы должны обновлять маркер времени активности пользователя. Он находится в БД. Как сэкономить?&lt;br /&gt;
Использовать Memcache конечно. Изначально, мы доверяем нашему Memcache, так как никто кроме нас туда &quot;залезть&quot; не может.&lt;br /&gt;
То есть и временную метку мы будем хранить тамже, как и сессию и логин.&lt;br /&gt;
Тогда, расходы по считыванию из БД у нас возникнут только при сбросе Memcache.&lt;br /&gt;
Рабочий момент - обновлять метку времени в самой БД, если она удовлетворяет правилу - не больше суток dt не нужно.&lt;br /&gt;
В таком варианте обновление БД и расходы будут только когда дельта времени уже выйдет за дозволенные рамки. И только тогда нам необходимо будет обновлять метку сессии и времени. А это уже черевато либо логином, либо &quot;доверяем&quot; - хотя есть еще варианты.&lt;br /&gt;
Имеем гарантированный &quot;расход&quot; на запись только при:&lt;br /&gt;
Аутентификации.&lt;br /&gt;
Выходе из системы.&lt;br /&gt;
Просрочке метки времени в БД более установленного нами интервала.&lt;br /&gt;
&lt;br /&gt;
Регулируется нагрузка на БД в нашем варианте двумя параметрами - времени жизни кукис и разрешенным интервалом активности сессии на сервере.&lt;br /&gt;
Регулируя первый - изменяем количество запросов на чтение.&lt;br /&gt;
Регулируя второй параметр - количество запросов на запись.&lt;br /&gt;
&lt;br /&gt;
Борьба с ботами и зловредами монтируется отдельно. Варианты есть.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/8806708021540779205/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2014/04/google-app-engine.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/8806708021540779205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/8806708021540779205'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2014/04/google-app-engine.html' title='Google App Engine - система авторизации и аутентификации пользователей. Регулируем и экономим.'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-1650079579890216105</id><published>2013-12-17T10:23:00.003+03:00</published><updated>2013-12-17T10:26:14.042+03:00</updated><title type='text'>DocPad. Документация по-русски</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Что такое DOCPAD?&lt;/h2&gt;
Мода на генераторы статических сайтов не пройдет никогда, и вот одним из таких инструментов для управления и создания сайтов является DocPad. Он создан на основе Node.js и Express.js.&lt;br /&gt;
Описывать установку, пожалуй не буду, перейду сразу к докам для начинающих.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
С чего начинается создание сайта с помощью DocPad?&lt;/h3&gt;
Ну конечно же с папки в которой все будет хранится! )))&lt;br /&gt;
Ну и как предлагает нам официальная документация (для стартового проекта используем рекомендуемое имя), назовем папку my-new-website, что по-ангельски означает &quot;мой-новый-вэбсайт&quot;!&lt;br /&gt;
Открываем командную строку Node.JS и топаем в папку с помощью команды:&lt;br /&gt;
&lt;b&gt;cd путь_к_папке/my-new-website&lt;/b&gt;&lt;br /&gt;
Запускаем docpad командной&lt;br /&gt;
&lt;b&gt;docpad run&lt;/b&gt;&lt;br /&gt;
Процесс пошел (в первый раз при запуске вам нужно будет согласится с предлагаемым множеством букав) и вам выпадет список предлагаемых заготовок-скелетонов. Нам нужен пустой (вводим цифирь 20)! Так что выбираем No Skeleton. Ну и ввод!&lt;br /&gt;
Побежит кучка строчек и все это дело в конце &quot;зависнет&quot; мигающим курсором.&lt;br /&gt;
Сие означает что наш сайт сгенерировался в первый раз и ожидает нас по адресу&amp;nbsp;&lt;a href=&quot;http://localhost:9778/&quot;&gt;http://localhost:9778/&lt;/a&gt;&lt;br /&gt;
Откроем его в браузере.. а там пока пусто.. что и следовало ожидать. Ну не совсем пусто..Тупо - текст &quot;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Not Found&quot;, что одно и тоже.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Вообщем процесс работает и отслеживает все дела. Чтобы прервать и вывести его из забытия давим CTRL-C и соглашаемся с предложением об амине.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;И что дальше?&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;После того, как мы выбрали No Skeleton, товарищ docpad создал в нашей папке проекта кучу своих подпапок по стандарту&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Нас интересует папочка src - там будут храниться закрома Родины. А сейчас там внутри три папки: documents, files и layouts.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Давайте создадим первую страницу сайта!&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Для этого в папке documents создаем пустой файл под названием index.html и напхаем в него обычного html-ного содержимого:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;i&gt;&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Welcome! | My Website&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;
Welcome!&lt;/h1&gt;
Welcome to My Website!&lt;br /&gt;

&lt;/body&gt;
&lt;/html&gt;&lt;/i&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;html&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;head&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;Welcome! | My Website&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;head&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;body&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;Welcome!&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;Welcome to My Website!&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;body&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;html&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Теперь топаем в нашу командную строку и заново запускаем docpad run!&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Открываем заветный &lt;a href=&quot;http://localhost:9778/&quot;&gt;http://localhost:9778/&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Ну и видим:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;b&gt;Welcome!&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;b&gt;Welcome to My Website!&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;И в чем прикол? Может без всей этой пурги можно было такой файлик создать, да открыть в хроме... Технологии однако.. Вот дальше и будет интереснее!&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Продолжение банкета. Шаблоны для ленивых.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Для того, чтобы не расслабляться, авторы предлагают создать нам еще одну страницу - About.html&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Ну послушаемся и пройдет в папку documents, где и создадим файл about.html&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Напихаем в него чего-нить символичного вроде:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;html&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;head&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;About Me | My Website&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;head&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;body&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;About Me&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;I like long walks on the beach. &lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;strong&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;Plus I rock at DocPad!&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;strong&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;body&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;html&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;i&gt;&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;About Me | My Website&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;
About Me&lt;/h1&gt;
I like long walks on the beach. &lt;strong&gt;Plus I rock at DocPad!&lt;/strong&gt;&lt;br /&gt;

&lt;/body&gt;
&lt;/html&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Кто не в теме - там про прогулки по пляжу и крутого перца, рулящего Docpad-ом. ))&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Вообщем имеем две страницы - index и about.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Открываем адресок &lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;a href=&quot;http://localhost:9778/about.html&quot;&gt;http://localhost:9778/about.html&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;А там опять нихрена... Ну так надо docpad остановить и запустить заново )))&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;И тогда нам явится что-то вроде:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;b&gt;About Me

I like long walks on the beach. Plus I rock at DocPad!&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Ну.. давайте еще десять страниц создадим? ))) Шучу ))&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Дальше товарищи создатели справедливо пишут - крутые перцы черную работу перекладывают на коней! Не будь конем!&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;И вот тут они предлагают пользоваться шаблонами.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Топаем в папку layouts и создаем файл default.html.eco&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;И не пугайтесь такого количества точек. Это значит что файл сначала обработается шаблонизатором eco ))&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Создатели тупо предлагают наполнить сей файл содержимым следующего рода:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;i&gt;&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;&lt;%= @document.title %&gt; | My Website&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;
&amp;lt;%= @document.title %&amp;gt;&lt;/h1&gt;
&amp;lt;%- @content %&amp;gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/i&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;html&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;head&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;vbscript&quot; style=&quot;box-sizing: border-box; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;%= @document.title %&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt; | My Website&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;head&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;body&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;vbscript&quot; style=&quot;box-sizing: border-box; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;%= @document.title %&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;vbscript&quot; style=&quot;box-sizing: border-box; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;%- @content %&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;body&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f2ead4; color: #232929; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #1c00cf; font-family: Monaco, Menlo, Consolas, &#39;Source Code Pro&#39;, &#39;courier new&#39;, monospace, serif; font-size: 11px; line-height: 16.799999237060547px; white-space: pre;&quot;&gt;&amp;lt;/&lt;span class=&quot;title&quot; style=&quot;box-sizing: border-box; color: #000088;&quot;&gt;html&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;И что это? Пока не знаем.. идем дальше!&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Далее, открываем наш старый файлик index.html и стираем всю ботву, что там писали. Взамен берем перо и пишем:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;i&gt;---
title: &quot;Welcome!&quot;
layout: &quot;default&quot;
isPage: true
---

Welcome to My Website!&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Каково? А это еще не все. Открываем еще и about.html и пишем вместо старых требухов:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;i&gt; ---
title: &quot;About Me&quot;
layout: &quot;default&quot;
isPage: true
---

I like long walks on the beach. &lt;strong&gt;Plus I rock at DocPad!&lt;/strong&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Вот оно чо, Михалыч! А чо это, собственно?&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Ну я не знаю, как вы, а я вижу, что зазря копипастил тучу текста )&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Теперь можно просто указать в файле title, файл шаблона, дать понять, что это страница (isPage-true), ну и после --- накалякать собственно содержимое, которое в файле шаблона будет выведено вместо &lt;/span&gt;&lt;i style=&quot;white-space: pre-wrap;&quot;&gt;&amp;lt;%- @content %&amp;gt;&lt;/i&gt;&lt;br /&gt;
&lt;i style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/i&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Ого! Технология, однако! Это ж куча времени теперь сэкономиться )))&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Но это только вступление.. Продолжение будет. А теперь срочно в библиотеку и читать что-нить от головы.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/1650079579890216105/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2013/12/docpad-na-russkom.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1650079579890216105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1650079579890216105'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2013/12/docpad-na-russkom.html' title='DocPad. Документация по-русски'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-1908788875403096599</id><published>2013-07-29T10:44:00.000+03:00</published><updated>2013-07-29T10:44:07.537+03:00</updated><title type='text'>Рассылка писем с помощью SendGrid из Google App Engine</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Этот пост от Адама ДюВандера, директора по коммуникациям в &lt;a href=&quot;http://www.sendgrid.com/&quot;&gt;SendGrid&lt;/a&gt;. SendGrid это облачный почтовый сервис, доставляющий электронную почту от имени компаний для улучшения связей и общения с клиентами. Интеграция новых или существующих систем почты осуществляется через SMTP или через REST API. В этом посте Адам рассказал как интегрировать SendGrid в приложение на Google App Engine.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Если вы разрабатываете приложения для Интернет или мобильной среды, вам необходим эффективный способ общения с клиентами. Создание и поддержание собственной инфраструктуры SMTP может занять много ресурсов и станет дорогим удовольствием. SendGrid исключает затраты и сложности по работе с электронной почтой, так что вы можете сосредоточиться на разработке своего следующего экстраординарного приложения.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Разработчики, использующие Google App Engine могут легко интегрировать SendGrid в собственные приложения. В примере ниже я покажу вам, как использовать нашу библиотеку Python. Java и PHP разработчики также имеют такую возможность. Любой разработчик Google App Engine может зарегистрироваться на SendGrid и рассылать бесплатно 25000 писем ежемесячно, так что ждем Вас!&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Сначала, скопируйте &lt;a href=&quot;https://github.com/sendgrid/sendgrid-python&quot; target=&quot;_blank&quot;&gt;библиотеку Python SendGrid&lt;/a&gt; в ваш проект в соответствующую папку. Когда вы импортируете эту библиотеку в ваше приложение, вы сможете создавать экземпляры SendGrids и рассылать почту с помощью простых команд.&lt;/div&gt;
Итак, вначале:&lt;br /&gt;
from sendgrid import Sendgrid&lt;br /&gt;
from sendgrid import Message&lt;br /&gt;
&lt;br /&gt;
Теперь, в приложении можно отсылать почту с помощью нескольких строк:&lt;br /&gt;
# make a secure connection to SendGrid&lt;br /&gt;
s = sendgrid.Sendgrid(&#39;&#39;, &#39;&#39;, secure=True)&lt;br /&gt;
# make a message object&lt;br /&gt;
message = sendgrid.Message(&quot;from@mydomain.com&quot;, &quot;message subject&quot;, &quot;plaintext message body&quot;,&lt;br /&gt;
&quot;&lt;strong&gt;HTML message body&lt;/strong&gt;&quot;)&lt;br /&gt;
# add a recipient&lt;br /&gt;
message.add_to(&quot;someone@example.com&quot;, &quot;John Doe&quot;)&lt;br /&gt;
# use the Web API to send your message&lt;br /&gt;
s.web.send(message)&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Также SendGrid предоставляет информацию о ваших письмах, например с помощью EventAPI вы можете узнать когда была доставлена, прочитана почта и множество других событий.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/1908788875403096599/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2013/07/sendgrid-google-app-engine.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1908788875403096599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1908788875403096599'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2013/07/sendgrid-google-app-engine.html' title='Рассылка писем с помощью SendGrid из Google App Engine'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-6974361003754793934</id><published>2012-11-08T22:01:00.002+03:00</published><updated>2012-11-08T22:01:30.789+03:00</updated><title type='text'>Новости блога Google AppEngine</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
6 ноября в&lt;a href=&quot;http://googleappengine.blogspot.ru/2012/11/upgrading-to-python-27-simple-and.html?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed:+GoogleAppEngineBlog+(Google+App+Engine+Blog)&quot;&gt; блоге появилась статья общего характера&lt;/a&gt;, в которой говориться следующее:&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
С момента появления новой среды Python версии 2.7 в феврале на нее успели перейти более половины всех активных приложений AppEngine.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Что же такого замечательного пришло вместе с Python 2.7? Это не просто обновление версии языка, это множество улучшений и изменений, способных значительно повлиять на эффективность выполнения приложений в среде Google AppEngine.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;b&gt;Увеличение эффективности параллельных запросов.&lt;/b&gt; Теперь всего лишь один фронтенд-экземпляр может обрабатывать сразу несколько запросов одновременно в разных потоках. А это значит, что теперь AppEngine требуется значительно меньше экземпляров для обработки того же объема трафика, а это значит значительное уменьшение стоимости работы сервиса.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Небольшая, но энергично-растущая компания мобильных игровых приложений &lt;a href=&quot;http://pocketgems.com/&quot;&gt;Pocket Gems&lt;/a&gt; смогла снизить расходы на запуск фронтенд-экземпляров на 78%, когда они перешли на работу со средой Python 2.7. &quot;Мы сразу же увидели значительную разницу.&quot; - заявил технический директор Дэвид Ундерхил. Нам теперь было достаточно лишь одной трети ресурсов, работающих на Python 2.7, чтобы справляться с тем же объемом трафика и задач под Python 2.5.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;b&gt;Более быстрые и более &quot;нативные&quot; С модули.&lt;/b&gt; В среду Google AppEngine были добавлены более быстрые &quot;нативные&quot; С-модули. Базовые библиотеки, такие как например cPickle выполняются значительно быстрее, чем их эквиваленты в среде исполнения Python 2.5.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Воспользуйтесь популярными сторонними библиотеками вроде PIL или NumPy. Мы значительно расширили количество библиотек сторонних разработчиков, которые теперь можно использовать в Google AppEngine Python 2.7.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/6974361003754793934/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2012/11/google-appengine.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6974361003754793934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6974361003754793934'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2012/11/google-appengine.html' title='Новости блога Google AppEngine'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-5399862899671560140</id><published>2012-08-21T22:48:00.002+03:00</published><updated>2012-08-21T22:48:40.579+03:00</updated><title type='text'>Google Apps Script - язык для удобства )</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
В поисках материалов по интернету о Google App Engine попалась информация по интересному проекту Google Apps Script. Очень многообещающе - начал изучать. Очередной сюрприз от Google для меня :) Не устаю удивляться.&lt;div&gt;
Надо будет попереводить, потренироваться.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/5399862899671560140/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2012/08/google-apps-script.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/5399862899671560140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/5399862899671560140'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2012/08/google-apps-script.html' title='Google Apps Script - язык для удобства )'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-1468122672829582060</id><published>2012-05-29T19:48:00.000+03:00</published><updated>2012-05-29T19:48:24.120+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="App Engine"/><category scheme="http://www.blogger.com/atom/ns#" term="Google"/><title type='text'>Google App Engine. Обзор хранилища данных</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Хранение данных&lt;/span&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/docs/python/datastore/overview&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;https://developers.google.com/appengine/docs/python/datastore/overview&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Среда App Engine предоставляет несколько вариантов для хранения данных:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;App Engine Datastore предоставляет NoSQL безсхемное хранилище с языком запросов и атомарными транзакциями&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt; Google Cloud SQL предоставляет &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;реляционную SQL базу данных для приложений App Engine, основываясь на знакомой базе MySQL&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Google Cloud Storage предоставляет сервис хранения для объектов и файлов &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;размером до терабайтов&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Python API хранилища данных&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;App Engine Datastore это безсхемное объектное хранилище предоставляющее надежное, масштабируемое хранилище для вашего вэб-приложения без плановых простоев, с атомарными транзакциями, высокодоступными чтением и записью, строгой согласованностью при запросах &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;чтения и в конечном итоге всех иных запросов. Интерфейс хранилища включает в себя обширное API моделирования данных и похожий на SQL язык запросов, называемый GQL.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Вступление&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Хранилище App Engine содержит объекты с данными, так называемыми сущностями. Сущность имеет одно или множество свойств — именованных значений одного из нескольких поддерживаемых типов данных: например свойство может быть строкой, числом &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;или ссылкой на другую сущность. Каждая сущность идентифицируется по виду &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;(типу), который определяет ее для выполнения запросов, а также уникальный &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;ключ, который идентифицирует ее внутри этого вида.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Хранилище может выполнять множество &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;операций в одной транзакции. По-определению транзакция не может быть успешно &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;закончена, пока каждая из ее операций не выполнена успешно, если любая из операций прервана, следует автоматический откат транзакции. Это особенно полезно при распределенных приложениях где множество пользователей могут одновременно получать доступ или манипулировать одними данными в один &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;момент времени.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Репозитарий данных&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Основной репозитарий данных App Engine это High Replication Datastore (HRD), высокореплицируемое хранилище, в котором данные реплицируются во множестве центров данных с помощью системы, основанной на алгоритме Pasox. Это предоставляет высокий уровень доступности для чтения и записи. Большинство запросов в конечном счете &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;согласованы. &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;background-color: #f4cccc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Второй вариант хранилища — Master/Slave перестал поддерживаться в апреле 2012 года. Хотя Google продолжает поддержку Master/Slave хранилищ в соответствии с условиями обслуживания, рекомендуется чтобы все новые приложения использовали HRD, а уже существующие приложения использующие Master/Slave хранилища мигрировали на HRD. Только HRD поддерживается в Python 2.7.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Сравнение с традиционными базами данных&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;В отличие от традиционных реляционных БД, App Engine использует распределенную архитектуру для &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;автоматического управления масштабированием до очень больших наборов данных. И несмотря на то, что интерфейс хранилища имеет множество похожих на традиционные БД возможностей он отличается от них тем, как описываются связи между &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;объектами данных. Сущности одного типа могут иметь различные свойства, а различные сущности могут иметь свойства с теми же именами но другими типами значений.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Эти уникальные характеристики предполагают иные пути для моделирования и управления данными для получения возможности автоматического масштабирования. В частности App Engine отличается от традиционных реляционных БД по следующим важным характеристикам:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;- App Engine спроектирована для масштабирования, позволяющего приложениям обеспечивать высокую производительность при большом трафике:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;запись в хранилище масштабируется автоматически распределяется по мере необходимости&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;чтение из хранилища масштабируется так как единственные поддерживаемые запросы те, чья производительность масштабируется согласно результирующему выходному набору данных (в отличие от просто набора данных). Это означает что запрос, выдающий в ответе 100 сущностей выполняется также как если бы поиск происходил по сотням или миллионам записей. Это свойство - ключевая причина, по которой не поддерживаются некоторые типы запросов.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;- так как все запросы в App Engine строятся на основе предварительно построенных индексов, типы запросов, которые могут выполняться более ограничены, чем позволенные в реляционных базах данных. В частности не поддерживаются следующие типы запросов:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Join-операции объединения&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;фильтрация по неравенству по нескольким свойствам&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;фильтрация или данные, основанные на результатах вложенных запросов&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;- В отличии от традиционных реляционных баз данных, хранилище App Engine может работать с сущностями одного типа с различными не строго определенными наборами наборами свойств (хотя вы можете сами наложить эти ограничения в приложении). В настоящий момент невозможно выполнить запрос, возвращающий только подмножество результирующих свойств сущностей.&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;b id=&quot;internal-source-marker_0.47334165195934474&quot; style=&quot;font-weight: normal; text-align: -webkit-auto;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Для получения более детальной информации по архитектуре хранилища читайте нашу серию статей &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/articles/datastore/overview&quot;&gt;&lt;span style=&quot;background-color: white; color: #1155cc; font-family: Arial; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Mastering the Datastore&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: white; color: #333333; font-family: Arial; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Введение в Python Datastore API&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;В Python сущности хранилища создаются из объектов Python; атрибуты объекта становятся свойствами сущности. Для создания новой сущности вы вызываете базовый класс родительской сущности (если таковая имеется), устанавливает атрибуты объектов, а затем сохраняет объект (вызывая такой метод как put()).&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; datetime&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; google&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;appengine&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;ext &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; db&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; google&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;appengine&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;api &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; users&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Employee&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;db&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;name &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;StringProperty&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;role &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;StringProperty&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; choices&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #008800; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;executive&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #008800; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;manager&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #008800; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;producer&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;]))&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;hire_date &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;DateProperty&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;new_hire_training_completed &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;BooleanProperty&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;indexed&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;account &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;UserProperty&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;e &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Employee&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #008800; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;role&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #008800; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;manager&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;account&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;get_current_user&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;())&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;hire_date &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; datetime&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;datetime&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;API хранилища предоставляет два интерфейса для запросов: интерфейс объектных запросов и похожий на SQL язык запросов, называемый GQL. Запрос возвращает сущности в форме экземпляра объекта класса модели, который можно изменить и обратно поместить в хранилище:&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;training_registration_list &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #008800; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;Alfred.Smith@example.com&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;),&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;users&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #008800; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;jharrison@example.com&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;),&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;users&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #008800; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;budnelson@example.com&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;employees_trained &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #660066; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;GqlQuery&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #008800; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&quot;SELECT * FROM Employee WHERE account IN :1&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;training_registration_list&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; e &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; employees_trained&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;e&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;new_hire_training_completed &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #000088; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &amp;nbsp;db&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #666600; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Сущности&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Объекты в хранилище App Engine известны как сущности. Сущность имеет одно или несколько именованных свойств, каждое из которых может иметь одно или несколько значений. Значения свойств могут быть данными &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/docs/python/datastore/entities#Properties_and_Value_Types&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;различного типа&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;, включая целые числа, числа с плавающей запятой, строки, даты, бинарные данные и многие другие. Запрос по свойству с множеством значений проверяет, соответствует ли какое-нибудь из значений нужному критерию запроса. Такие свойства очень удобны при проверке совокупности значений.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Примечание: сущности хранилища безсхемные, как в традиционных реляционных БД, хранилище App Engine не требует, чтобы все сущности одного типа имели одинаковый набор свойств или чтобы все значения свойств сущности были одинакового типа данных. Если потребуется формальная схема. то само приложение ответственно за то, чтобы сущности соответствовали ей; Python SDK включает богатую библиотеку возможностей моделирования данных для этого.&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Типы, ключи и идентификаторы&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Каждая сущность хранилища имеет свой тип или вид, который классифицирует сущность по назначению запроса: например, приложение управления человеческими ресурсами может представлять каждого работника в компании с помощью сущности типа Employee. Также, каждая сущность имеет собственный ключ, который однозначно ее идентифицирует. Ключ состоит из следующих компонентов:&lt;/span&gt;&lt;/div&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Тип сущности&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Опциональный родительский путь определяющий сущность в иерархии хранилища&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Идентификатор, который может быть:&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;ключевой строкой&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;целым числом ID&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Идентификатор ассоциируется с сущностью при ее создании. Так как он является частью ключа сущности, он ассоциируется с сущностью навсегда и не может изменяться. Он может быть присвоен двумя путями:&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Ваше приложение может само указать ключевую строку-значение для сущности&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Вы можете определить для хранилища автоматическое присвоение идентификатору численное значение ID&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Примечание: вместо именованных строковых значений или генерирования числовых значений ID автоматически, сложные приложения могут иногда присваивать собственные числовые значения ID сущностям, которые они создают. Будьте внимательны, если вы выберите этот путь, вам придется предпринять специальные меры, чтобы предотвратить возможные конфликты вручную присвоенных ID с автоматически-сгенерированными хранилищем, смотрите &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/docs/python/datastore/entities#Kinds_and_Identifiers&quot;&gt;&lt;span style=&quot;background-color: #e6b8af; color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Сущности, свойства и Ключи&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; для подробной информации.&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Родительские пути&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Сущности в хранилище формируют иерархическую структуру, похожую на структуру директорий файловой системы. При создании сущности вы опционально можете указать другую сущность как родительскую; новая сущность будет потомком родительской сущности. Эта связь между сущностью и ее родителем неразрывна и ее нельзя будет изменить после ее создания. Сущность у которой нет родителя является корневой (root) сущностью. Хранилище никогда не присвоит двум сущностям с одинаковым родителем одинаковый ID, также как и двум корневым сущностям.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Родитель сущности, родитель родителя и так далее по рекурсии являются предками. Ее наследники, потомки потомков называются потомками. Сущность и ее потомки принято называть одной группой потомков. Последовательность сущностей, начиная с корневой и следую от родителя к потомкам до указанной сущности составляю родительский путь или путь предков сущности. Полный ключ, идентифицирующий сущность состоит из последовательности пар идентификатор-тип, указывающих их родительский путь и заканчивающихся на самой сущности:&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: #fafafa; color: #007000; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Person:GreatGrandpa / Person:Grandpa / Person:Dad / Person:Me&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;У корневой сущности родительский путь пуст и ключ состоит только из собственно типа и идентификатора.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: #fafafa; color: #007000; font-family: Verdana; font-size: 13px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Person:GreatGrandpa&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Запросы и индексы&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Кроме прямого получения сущностей из хранилища по их ключам, приложение может выполнять запрос для их получения по значениям свойств. Запрос работает с сущностями указанного типа, он может фильтровать сущности по значениям свойств или ключей и может возвращать ноль и более сущностей в результате. (Для экономии памяти и увеличения производительности запросу следует где возможно указывать лимит на количество результирующих данных). Запросу также можно указать порядок сортировки по значениям свойств. Результат включает все сущности, которые имеют хотя бы одно (возможно нулевое) значение для каждого свойства, указанного в фильтре и порядке сортировки и свойства которых соответствуют указанному в фильтре критерию. Запрос может возвращать всю сущность, ее проекцию или только ключи.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Запрос может также включать родительский фильтр, ограничивающий результаты только группой потомков указанного родителя. Такие запросы известны также как родительские запросы. По-умолчанию родительские запросы возвращают строго соответствующие результаты, которые гарантировано синхронизированы с последними изменениями в данных. Неродительские запросы напротив, могут охватывать все хранилище, а не только одну группу сущностей, которые в конечном счете соответствуют реальным, но могут возвращать устаревшие данные. Если приложению важно строгое соответствие, то вам необходимо учесть это при структурировании данных, размещая связанные сущности в той же группе сущностей, так что их можно будет получить с помощью родительского а не обычного запроса; смотрите для подробностей &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/docs/python/datastore/structuring_for_strong_consistency&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Структурирование данных для точной согласованности&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Примечание: соблюдение согласованности немного отличается в Master/Slave хранилищах; смотрите &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/docs/python/datastore/usingmasterslave&quot;&gt;&lt;span style=&quot;background-color: #e6b8af; color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Использование Master/Slave хранилищ&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; для детального ознакомления.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Помимо фильтров &amp;nbsp;в запросе можно указать порядок сортировки по значениям свойств. Результаты запроса будут включать все сущности, которые имеют по крайней мере одно (возможно нулевое) значение для каждого свойства, указанного в фильтре и порядке сортировки и чьи свойства соответствуют указанным критериям фильтра. Запрос может возвращать целиком сущности, указанное подмножество их свойств или просто их ключи (в ключевых запросах).&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Примечание: для экономии памяти и увеличения производительности запросы следует где только возможно ограничивать по количеству выдаваемых результатов.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Каждый запрос использует индекс - таблицу, содержащую потенциальные результаты запроса в необходимом порядке. Хранилище обновляет индексы постепенно для отражения любых изменений, которые приложение делает с сущностями. Таким образом, корректные результаты всех запросов мгновенно доступны напрямую из индексов, без необходимости проведения дополнительных расчетов.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Индексы для некоторых типов запросов предоставляются автоматически; приложение может определить дополнительные индексы для себя в файле индексной конфигурации под названием index.yaml. Вэб сервер разработчика автоматически добавляет предложения в конфигурационный файл, когда находит запросы, у которых еще не сконфигурированы индексы. Вы можете вручную настроить индексы, отредактировав файл перед загрузкой приложения, смотрите статью &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/articles/indexselection.html&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Выбор индексов и расширенный поиск&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; для дополнительной информации.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Примечание: Этот индексный механизм поддерживает широкий спектр запросов и подходит для большинства приложений. Однако он не поддерживает некоторые типы запросов, общие для других технологий БД, в частности объединение и запросы агрегирования не поддерживаются в это механизме запросов.&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Транзакции&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Каждая попытка создать, обновить или удалить сущность происходит в контексте транзакции. Отдельная транзакция может содержать любое количество таких операций. Для поддержки целостности данных, транзакция проходит если все ее операции применены к хранилищу успешно как блок или если хоть одна не завершилась успешно, отменяется весь &amp;nbsp;блок операций.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Вы можете выполнить множество действий с сущностью внутри одной транзакции. Например для увеличения поля счетчика объекта вам необходимо считать значение счетчика, рассчитать новое значение и сохранить его обратно. Без использования транзакции возможна ситуация, когда другой процесс изменит значение поля счетчика в промежуток времени между тем, когда вы его прочитали и моментом обновления счетчика и ваше приложение перезапишет это значение своим.Использование транзакций обеспечит уверенность в том, что никакой другой процесс в это время не повлияет на данные.&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Транзакции и группы сущностей&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Внутри транзакции разрешены только родительские запросы, а это значит что каждый запрос ограничен одной отдельной группой сущностей. Однако сама по себе транзакция может применяться к множеству сущностей, которые могут как принадлежать к отдельной группе (в случае кросс-групповых транзакций) так и включать до пяти различных групп сущностей.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Хранилище использует оптимистичный параллелизм для управления транзакциями. Когда два и более экземпляров приложения пытаются изменить одну группу сущностей в один момент времени (как обновляя сущности так и создавая новые), первое приложение пытающееся внести изменение сможет это сделать, а другие нет. Эти другие приложения могут позже попытаться еще раз внести изменения в уже обновленные первым приложением данные. Помните, что это ограничивает количество параллельных записей, которые вы можете сделать в любую сущность в данной группе сущностей.&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Кросс-групповые транзакции&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Транзакция с сущностями, принадлежащими к разным группам, называется кросс-групповая (XG) транзакция. В пределах одной транзакции можно работать максимум с пятью группами сущностей и будет завершена успешно, если ни одна из групп не будет затронута другими параллельными транзакциями. &lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;В транзакции с одиночной группой вы не можете выполнять неродительские запросы в XG транзакции. Однако вы можете выполнять родительские запросы на отдельных группах сущностей. Нетранзакционные (неродительские) запросы могут видеть все, некоторые или никакие результаты предыдущих выполненных транзакций (подробнее об этом в &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/docs/python/datastore/overview#Datastore_Writes_and_Data_Visibility&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Запись в хранилище и видимость данных&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;). Однако такие нетранзакционные запросы лучше всего подходят, чтобы увидеть результаты частично выполненной XG транзакции, чем такие же частично выполненные одиночные групповые транзакции.&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Примечание: первая попытка чтения группы сущностей при XG запросах может вызвать исключение &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/docs/python/datastore/exceptions#TransactionFailedError&quot;&gt;&lt;span style=&quot;background-color: #e6b8af; color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;TransactionFailedError&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;, если есть конфликт с другой транзакцией, работающей с этой группой сущностей в этот момент. Это означает, что даже XG транзакция, пытающаяся просто считать данные потерпит неудачу и вызовет исключение согласованности данных.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;XG транзакция, которая затрагивает только одну группу сущностей ведет себя также как транзакция с одиночной группой. Операции в такой транзакции имеют такую же производительность и стоимость как и эквивалентная одиночно-групповая транзакция с экономией ресурсов и биллинга, но с более высокой задержкой.&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Запись в хранилище и видимость данных.&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Примечание: эта секция описывает работу с High replication datastore (HRD). Устаревшие Master/Slave хранилища ведут себя по-другому; смотрите Использование &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/docs/python/datastore/usingmasterslave%22&quot;&gt;&lt;span style=&quot;background-color: #e6b8af; color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Master/Slave хранилища&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;. Для дополнения к этому топику смотрите также статьи &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/articles/life_of_write&quot;&gt;&lt;span style=&quot;background-color: #e6b8af; color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Жизнь записи в хранилище&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; и &lt;/span&gt;&lt;a href=&quot;https://developers.google.com/appengine/articles/transaction_isolation&quot;&gt;&lt;span style=&quot;background-color: #e6b8af; color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Изоляция транзакций в App Engine&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;. &lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;background-color: #e6b8af; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Данные записываются в хранилище в две фазы:&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;1. В фазе фиксации (Commit) данные сущности записываются в журнал&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;2. Фаза применения состоит из двух параллельных действий:&lt;/span&gt;&lt;/div&gt;
&lt;ul style=&quot;margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Данные сущности записываются&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: Arial; font-size: 15px; list-style-type: disc; vertical-align: baseline;&quot;&gt;&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Записывается индексный ряд для сущности (этот процесс может занять больше времени чем простая запись данных)&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Операция записи возвращается сразу после фазы Commit а фаза применения происходит асинхронно. Если произошла ошибка при первом шаге Commit, то он автоматически повторяется, однако если ошибки продолжаются, хранилище возвращает сообщение об ошибке, которое ваше приложение принимает как исключение. Если Commit фаза проходит, а фаза применения вызывает ошибку то она переносится вперед до завершения пока не произойдет следующее:&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Периодическая зачистка хранилища на предмет незавершенных Commit операций и их применение&lt;/span&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;margin-bottom: 0pt; margin-top: 0pt; text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Некоторые операции применения (get, put, delete и родительские запросы) которые используют затронутые группы сущностей не будут выполнятся пока не будут завершены предыдущие предыдущие.&lt;/span&gt;&lt;/div&gt;
&lt;/b&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/1468122672829582060/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2012/05/google-app-engine.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1468122672829582060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1468122672829582060'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2012/05/google-app-engine.html' title='Google App Engine. Обзор хранилища данных'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-1770557286273397958</id><published>2012-05-24T23:48:00.003+03:00</published><updated>2012-05-24T23:55:19.920+03:00</updated><title type='text'>Работа с изображениями на canvas с помощью JavaScript</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Начинаем&lt;br /&gt;
&lt;br /&gt;
Настало время что-нибудь нарисовать  на нашем экране. Сначала нам понадобится HTML страница на которой собственно и будет отображаться canvas элемент.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;text-align: -webkit-auto;&quot;&gt;&lt;code&gt;&lt;span style=&quot;color: #ff0080;&quot;&gt;
&lt;/span&gt;
&lt;/code&gt;     &amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;&amp;gt;
     &amp;lt;html lang=&quot;en&quot;&amp;gt;
        &amp;lt;head&amp;gt;
           &amp;lt;title&amp;gt;JavaScript Platformer 1&amp;lt;/title&amp;gt;
           &amp;lt;script type=&quot;text/javascript&quot; src=&quot;jsplatformer1.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
           &amp;lt;style type=&quot;text/css&quot;&amp;gt;
              body { font-family: Arial,Helvetica,sans-serif;}
           &amp;lt;/style&amp;gt;
        &amp;lt;/head&amp;gt;
       &amp;lt;body&amp;gt;
          &amp;lt;p&amp;gt;
             &amp;lt;a href=&quot;http://www.brighthub.com/internet/web-development/articles/38364.aspx&quot;&amp;gt;
                Game Development with Javascript and the canvas element
             &amp;lt;/a&amp;gt;
          &amp;lt;/p&amp;gt;
          &amp;lt;canvas id=&quot;canvas&quot; width=&quot;600&quot; height=&quot;400&quot;&amp;gt;
             &amp;lt;p&amp;gt;Your browser does not support the canvas element.&amp;lt;/p&amp;gt;
          &amp;lt;/canvas&amp;gt;
       &amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;&lt;/pre&gt;
&lt;br class=&quot;Apple-interchange-newline&quot; /&gt;&lt;br /&gt;
В коде страницы все достаточно просто и понятно. Есть два важных элемента:&lt;br /&gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;jsplatformer1.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
Эта строчка подключает файл с кодом JavaScript, с помощью которого будет изменяться canvas элемент, который будет описан ниже.&lt;br /&gt;
&amp;lt;canvas id=&quot;canvas&quot; width=&quot;600&quot; height=&quot;400&quot;&amp;gt;

&amp;lt;p&amp;gt;Your browser does not support the canvas element.&amp;lt;/p&amp;gt;

&amp;lt;/canvas&amp;gt;&lt;br /&gt;
Так мы создаем элемент canvas. Броузеры, которые не поддерживают элемент canvas, такие как IE (до версии 8), игнорируют его, отображая вместо него дочерний элемент. В нашем случае это простой параграф, предупреждающий пользователя. что их браузер не поддерживает элемент canvas. Все броузеры, которые этот элемент поддерживают - не отображают его дочерний элемент.&lt;br /&gt;
Атрибут ID элемента canvas очень важен, так как понадобится нам для получения ссылки на этот элемент с помощью JavaScript. Атрибуты ширины и высоты просто указывают размеры canvas, как и для других html элементов вроде таблицы или изображения.&lt;br /&gt;
Содержимое файла jsplatformer1.js:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;text-align: -webkit-auto;&quot;&gt;&lt;code&gt;&lt;span style=&quot;color: #ff0080;&quot;&gt;
&lt;/span&gt;   &lt;/code&gt;&lt;/pre&gt;
&lt;pre style=&quot;text-align: -webkit-auto;&quot;&gt;&lt;code&gt;
&lt;/code&gt;&lt;span style=&quot;color: #ff0080;&quot;&gt;
     // target frames per second
     const FPS = 30;
     var x = 0;
     var y = 0;
     var xDirection = 1;
     var yDirection = 1;
     var image = new Image();
     image.src = &quot;http://javascript-tutorials.googlecode.com/files/jsplatformer1-smiley.jpg&quot;;
     var canvas = null;
    var context2D = null;

    window.onload = init;

    function init()
    {
       canvas = document.getElementById(&#39;canvas&#39;);
       context2D = canvas.getContext(&#39;2d&#39;);
       setInterval(draw, 1000 / FPS);
    }

    function draw()
    {
       context2D.clearRect(0, 0, canvas.width, canvas.height);
       context2D.drawImage(image, x, y);
       x += 1 * xDirection;
       y += 1 * yDirection;

       if (x &amp;gt;= 450)
       {
          x = 450;
          xDirection = -1;
       }
       else if (x &amp;lt;= 0)
       {
          x = 0;
          xDirection = 1;
       }

       if (y &amp;gt;= 250)
       {
          y = 250;
          yDirection = -1;
      }
       else if (y &amp;lt;= 0)
       {
          y = 0;
          yDirection = 1;
       }
    }&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Сам по себе элемент canvas достаточно прост и бесполезен. Необходимо с помощью JavaScript что-нибудь отрисовывать на canvas и в нашем случае этот код находится в файле jsplatformer1.js. В качестве простого примера мы загружаем изображение, отрисовываем его на canvas и двигаем его.&lt;br /&gt;
Сначала определим несколько глобальных переменных:&lt;br /&gt;
const FPS = 30;&lt;br /&gt;
FPS определяет частоту с которой будет перерисовываться canvas.&lt;br /&gt;
var x = 0;
var y = 0;
var xDirection = 1;
var yDirection = 1;&lt;br /&gt;
Переменные x, y, xDirection и yDirection используются для определения положения изображения (относительно левого верхнего угла canvas) и указывают направление движения изображения.&lt;br /&gt;
var image = new Image();
image.src = &quot;http://javascript-tutorials.googlecode.com/files/jsplatformer1-smiley.jpg&quot;;&lt;br /&gt;
&lt;br /&gt;
Чтобы отрисовать изображение на canvas нам сначала необходимо загрузить это изображение. Для этого мы создаем объект Image и устанавливаем свойство src на месторасположение этого файла.&lt;br /&gt;
&lt;br /&gt;
var canvas = null;&lt;br /&gt;
var context2D=null;&lt;br /&gt;
&lt;br /&gt;
Нам также понадобится ссылка на элемент canvas, также как и на отрисовывамый контекст. Мы присвоим необходимые значения элементу позже, а пока оставим их в null.&lt;br /&gt;
&lt;br /&gt;
windows.onload = init;&lt;br /&gt;
&lt;br /&gt;
В конце нам необходимо дать знать, когда страница будет загружена, чтобы запустить код который отрисует canvas, поэтому мы указываем функцию init, которая будет вызвана при отработке события окна после загрузки.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/1770557286273397958/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2012/05/canvas-javascript.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1770557286273397958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1770557286273397958'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2012/05/canvas-javascript.html' title='Работа с изображениями на canvas с помощью JavaScript'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-1282376054941575398</id><published>2012-05-24T22:57:00.003+03:00</published><updated>2012-05-24T23:00:42.761+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="html 5"/><title type='text'>html 5. Об элементе Canvas</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;teaser&quot; style=&quot;font-family: Arial, Helvetica; text-align: -webkit-auto;&quot;&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;Элемент canvas появившийся в JavaScript движках наряду с некоторыми другими возможностями дает вэб-разработчикам возможность создавать детализированные и интерактивные 2D вэбстраницы без использования сторонних 3D плагинов. В этом топике обсудим некоторые возможности canvas и его потенциальные возможности.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: white; color: #252525; line-height: 1.5em;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;color: #252525; line-height: 1.5em;&quot;&gt;&lt;b style=&quot;background-color: white;&quot;&gt;JavaScript и элемент Canvas&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: white; color: #252525; line-height: 1.5em;&quot;&gt;HTML начал жизнь как формат для статичных страниц. Анимированные GIF изображения и мигающий текст - вот и вся динамика, которую он мог предоставить. JavaScript изменил все, позволяя динамическое изменение вэб-страниц и многие вэб-сервисы теперь используют и технологию AJAX для создания сайтов, которые дают пользователю более привычную работу, чем &quot;нажал, обновилась страница, нажал&quot;, которая обычно так часто используется в обычных html-страницах.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;bhSec bhSec_String&quot; style=&quot;font-family: Arial, Helvetica; line-height: 1.5em; text-align: -webkit-auto;&quot;&gt;
&lt;div class=&quot;KonaBody&quot;&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;К сожалению, JavaScript несколько ограничен функциональностью браузеров, в которых он работает. И если вы вполне можете создавать и изменять элемент на странице, то с помощью JavaScript вы не сможете (просто) заставить клиентскую машину отображать новый тип объектов. JavaScript может изменять текст, вставлять изображение или с легкостью изменять таблицу, так как эти элементы уже поддерживаются в HTML. Но что, если вы захотите чего-то больше, как например создать игру? Все, что вы могли использовать это стандартные элементы html таким образом, для которого они вовсе не предназначены. Ну или вам пришлось бы использовать плагины вроде Flash или Silverlight.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;Появился элемент canvas. Этот новый HTML элемент предоставляет возможность JavaScript разработчикам рисовать прямо на странице без использования плагинов. Он впервые был представлен компанией Apple в их фреймворке WebKit и используется браузером Safari и виджетами Dashboard. Элемент canvas теперь является частью html 5 и теперь поддерживается большинством браузеров, таких как Chrome, Firefox, Opera и Konqueror. Internet Explorer (по-крайней мере до версии 8) &amp;nbsp;является исключением, хотя проекты вроде ExplorerCanvas предоставляют некоторую функциональность &amp;nbsp;элемента canvas в IE.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;Любой кто работал с программированием 2D графики увидит что использование элемента canvas достаточно легкое и простое. Вы можете рисовать линии, фигуры, градиенты и даже изменять отдельные пиксели с помощью функций, которые очень похожи на большинство подобных в других 2D API. И огромное спасибо производительности последних JavaScript движков Chrome V8, Firefox SpiderMonkey и Safari Nitro за то что создание детализированных и интерактивных вэб-приложений теперь вполне доступно.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;В этой серии статей мы посмотрим как создать простую игру с помощью JavaScript и элемента canvas. Мы раскроем такие темы как анимация, загрузка ресурсов, рендеринг слоев, прокрутка и взаимодействие.&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;inlineAd inlineAdOdd&quot; style=&quot;float: left; margin: 10px 10px 10px 0px;&quot;&gt;
&lt;div&gt;
&lt;div style=&quot;overflow: hidden;&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;clear: both;&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/1282376054941575398/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2012/05/html-5-canvas.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1282376054941575398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1282376054941575398'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2012/05/html-5-canvas.html' title='html 5. Об элементе Canvas'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-6986454462697117204</id><published>2010-07-30T13:28:00.004+03:00</published><updated>2010-07-30T13:37:54.392+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Мои записки"/><title type='text'>ExtJS и jQuery</title><content type='html'>Ну вот наконец стал использовать в рабочих проектах ExtJS и jQuery&lt;br /&gt;Ext конечно же использую для создания панелей управления сайтами - чудно и практично, а главное люди довольны что сами могут содержимым сайта управлять просто и понятно как в обычных программах, а не в лохматых непонятных самоделках или стандартных монстерских панелях открытых проектов, где сам чорт ногу сломит, не то что новичок.&lt;br /&gt;jQuery также приятно радует, отличная библиотечка для движка, динамика некоторых просто восхищяет, когда сайт &quot;расплывается&quot; и трансформируется или меняется расцветка прямо на их глазах :)&lt;br /&gt;Вообщем связка PHP MySQL jQuery ExtJS для меня теперь становиться стандартом :) Ну очень я не люблю всякий ширпотреб проектов &quot;на любой случай&quot;, хотя конечно не спорю - многим нравится. А я люблю проекты с &quot;индивидуальным подходом&quot;.&lt;br /&gt;Чего и всем желаю!</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/6986454462697117204/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2010/07/extjs-jquery.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6986454462697117204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6986454462697117204'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2010/07/extjs-jquery.html' title='ExtJS и jQuery'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-4039009586421151111</id><published>2009-01-20T10:22:00.001+02:00</published><updated>2009-01-20T10:24:23.037+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><title type='text'>jQuery 1.3</title><content type='html'>Вышел новый релиз jQuery - 1.3&lt;br /&gt;Отмечается значительное увеличение производительности и скорости работы библиотеки.&lt;br /&gt;&lt;a href=&quot;http://docs.jquery.com/Release:jQuery_1.3&quot;&gt;Подробнее&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/4039009586421151111/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2009/01/jquery-13.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/4039009586421151111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/4039009586421151111'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2009/01/jquery-13.html' title='jQuery 1.3'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-8650832292704308964</id><published>2009-01-03T09:00:00.000+02:00</published><updated>2009-01-03T09:01:44.180+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Создание приложений в ExtJS"/><title type='text'>Приложения в ExtJS</title><content type='html'>До того как начать&lt;br /&gt;&lt;br /&gt;Это пособие подразумевает, что вы уже установили ExtJS - JavaScript библиотеку и что она установлена в директории extjs в вышестоящей от текущей директории, где будет создаваться наше приложение. Если вы установили библиотеку в другом месте вам необходимо будет изменять пути которые мы употребляем в примерах.&lt;br /&gt;Что нам понадобится?&lt;br /&gt;&lt;br /&gt;Помимо ExtJS нам понадобится создать два файла:&lt;br /&gt;&lt;br /&gt;    * applayout.html&lt;br /&gt;    * applayout.js &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Давайте начнем с файлов с минимумом содержимого. Вот они с детальным описанием:&lt;br /&gt;&lt;br /&gt;applayout.html&lt;br /&gt;&lt;pre class=&quot;source source-html4strict&quot;&gt;&lt;span class=&quot;sc0&quot;&gt;&amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot; &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;sc0&quot;&gt;    &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;http-equiv&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;content&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/html; charset=utf-8&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;rel&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/css&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;../extjs/resources/css/ext-all.css&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;script&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;../extjs/adapter/ext/ext-base.js&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;script&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;../extjs/ext-all-debug.js&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;script&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;applayout.js&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;coMULTI&quot;&gt;&amp;lt;!-- A Localization Script File comes here --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;script&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        Ext.onReady(myNameSpace.app.init, myNameSpace.app);&lt;br /&gt;    &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;/span&gt;Application Layout Tutorial&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;btn1-ct&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Первые две строчки указывают тип документа. Наше приложение будет работать и без указания типа, однако в этом случае броузер перейдет в режим Quirks и приложение не станет совместимым с другими броузерами.&lt;br /&gt;Мы будем использовать HTML 4.0.1 спецификацию, потому что она поддерживается большинством броузеров. Конечно, вы можете использовать другой тип документа если захотите, однако важно помнить, что вы всегда должны указывать тип документа.&lt;br /&gt;&lt;br /&gt;ОБНОВЛЕНИЕ: Если вы будете указывать тип документа, то в броузерах IE (всех версиях) есть баги, которые могут вызвать непредсказуемые результаты выполнения. Поэтому больше не рекомундуется указывать тип документа в приложениях.&lt;br /&gt;&lt;br /&gt;После начала файла и заголовка head идет указание типа содержимого Content-Type. Ваше приложение будет работать и без него, но лучше указать его.&lt;br /&gt;&lt;br /&gt;Затем мы подключаем Ext стили, адаптер и ExtJS. Есть две версии ExtJS:&lt;br /&gt;    * ext-all.js - плохо-читаемый, загружается быстрее, используется для готовых приложений&lt;br /&gt;    * ext-all-debug.js - легко-читаемый, используется для разработки &lt;br /&gt;&lt;br /&gt;Мы собираемся разрабатывать, поэтому включаем вторую версию.&lt;br /&gt;Затем идет наше приложение applayout.js, а после него файлы локализации которые перекрывают английский текст в приложении applayout.js и ExtJS своим переводом, до того как приложение стартует.&lt;br /&gt;Теперь мы готовы установить обработчик событий, который инициализирует (стартует) наше приложение после того, как документ полностью загрузится.&lt;br /&gt;Строка&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;Ext.&lt;span class=&quot;me1&quot;&gt;onReady&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;myNameSpace.&lt;span class=&quot;me1&quot;&gt;app&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;init&lt;/span&gt;, myNameSpace.&lt;span class=&quot;me1&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;говорит: Когда документ полностью загрузился, запустить init метод myNameSpace.app в области myNameSpace.app&lt;br /&gt;Затем идет текст заголовка, конец head (пустой) и закрывающиеся тэги.&lt;br /&gt;Это все, что сейчас находится в html файле.&lt;br /&gt;applayout.js&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;coMULTI&quot;&gt;/**&lt;br /&gt;  * Application Layout&lt;br /&gt;  * by Jozef Sakalos, aka Saki&lt;br /&gt;  * http://extjs.com/learn/Tutorial:Application_Layout_for_Beginners&lt;br /&gt;  */&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// reference local blank image&lt;/span&gt;&lt;br /&gt;Ext.&lt;span class=&quot;me1&quot;&gt;BLANK_IMAGE_URL&lt;/span&gt; = &lt;span class=&quot;st0&quot;&gt;&#39;../extjs/resources/images/default/s.gif&#39;&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// create namespace&lt;/span&gt;&lt;br /&gt;Ext.&lt;span class=&quot;kw2&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;myNameSpace&#39;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// create application&lt;/span&gt;&lt;br /&gt;myNameSpace.&lt;span class=&quot;me1&quot;&gt;app&lt;/span&gt; = &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// do NOT access DOM from here; elements don&#39;t exist yet&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// private variables&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// private functions&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// public space&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;co1&quot;&gt;// public properties, e.g. strings to translate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        &lt;span class=&quot;co1&quot;&gt;// public methods&lt;/span&gt;&lt;br /&gt;        init: &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kw3&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;Application successfully initialized&#39;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;        &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;; &lt;span class=&quot;co1&quot;&gt;// end of app&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// end of file&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Первые строки этого файла это комментарии, объясняющие содержимое файла, автора и другую связанную информацию. Уверен, ваши приложения будут работать и без комментариев, но запомните: всегда пишите ваше приложение так, как будто пишите для другого человека. Когда вы когда-нибудь снова вернетесь к этому коду через пару месяцев и не сможете понять чтоже такое написано здесь, потому как нет комментариев, вы измените вашу практику кодирования. &lt;br /&gt;Затем идет ссылка на пустое изображение, указывающее на ваш собственный сервер взамен сервера по-умолчанию extjs.com. Вам ведь не надо загружать что-либо с extjs.com при каждой загрузке приложения, не так ли?&lt;br /&gt;Теперь мы создаем собственное пространство имен. Причина этого в инкапсуляции (изолированиии) всех переменных и методов в одном глобальном объекте чтоб избежать конфликтов имен переменных и избежать изменнений их значений извне. &lt;br /&gt;Ядро приложения в конце.. Мы создаем свойство app в myNameSpace как возвращаемое значение функции которая запускается немедленно.&lt;br /&gt;Если мы запустим следующий код&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; o = &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;p1:&lt;span class=&quot;nu0&quot;&gt;11&lt;/span&gt;, p2:&lt;span class=&quot;nu0&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Мы по-сути создаем анонимную функцию (функцию без имени) которая запускается сразу же после обработки (помните () полсе определения функции). Функция возвращает объект который привязывается к переменной о. Наше приложение будет использовать туже логику.&lt;br /&gt;Вы можете разместить инициализацию, частные переменные и\или определения частных функций между началом объявление функции и моментом возврата результата, но помните: Код запускается как часть заголовка и никакие html элементы еще не созданы поэтому любые попытки доступа к ним вызовут ошибку.&lt;br /&gt;С другой стороны, init функция это просто один из методов возвращаемых этой анонимной функцией, запускается только после того, как весь документ полностью загружен и вся структура DOM уже доступна.&lt;br /&gt;Дальше - больше. Если вы не сделали никаких ошибок вы получите сообщение об успехе когда запустите ваше приложение.&lt;br /&gt;Теперь идет самая сложная часть. Это написать что-то работающее внутри этого пустого шаблона.&lt;br /&gt;&lt;br /&gt;Public, Private, Privileged?&lt;br /&gt;&lt;br /&gt;Давайте добавим некоторую жизнь нашему приложению. Добавьте следующие строки в applayout.html внутрь тэга body:&lt;br /&gt;&lt;pre class=&quot;source source-html4strict&quot;&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;btn1-ct&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Это пустой div который послужит как контейнер для кнопки. Затем добавим парочку строк в applayout.js и вот что получится:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;coMULTI&quot;&gt;/**&lt;br /&gt;  * Application Layout&lt;br /&gt;  * by Jozef Sakalos, aka Saki&lt;br /&gt;  * http://extjs.com/learn/Tutorial:Application_Layout_for_Beginners&lt;br /&gt;  */&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// reference local blank image&lt;/span&gt;&lt;br /&gt;Ext.&lt;span class=&quot;me1&quot;&gt;BLANK_IMAGE_URL&lt;/span&gt; = &lt;span class=&quot;st0&quot;&gt;&#39;../extjs/resources/images/default/s.gif&#39;&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// create namespace&lt;/span&gt;&lt;br /&gt;Ext.&lt;span class=&quot;kw2&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;myNameSpace&#39;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// Just to allow this tutorial to work for 1.1 and 2.&lt;/span&gt;&lt;br /&gt;Ext.&lt;span class=&quot;me1&quot;&gt;Ext2&lt;/span&gt; = &lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;Ext.&lt;span class=&quot;me1&quot;&gt;version&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;Ext.&lt;span class=&quot;me1&quot;&gt;version&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; == &lt;span class=&quot;nu0&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// create application&lt;/span&gt;&lt;br /&gt;myNameSpace.&lt;span class=&quot;me1&quot;&gt;app&lt;/span&gt; = &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// do NOT access DOM from here; elements don&#39;t exist yet&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// private variables&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; btn1;&lt;br /&gt;    &lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; privVar1 = &lt;span class=&quot;nu0&quot;&gt;11&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// private functions&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; btn1Handler = &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;button, event&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;kw3&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;privVar1=&#39;&lt;/span&gt; + privVar1&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;        &lt;span class=&quot;kw3&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;this.btn1Text=&#39;&lt;/span&gt; + &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;btn1Text&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// public space&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;co1&quot;&gt;// public properties, e.g. strings to translate&lt;/span&gt;&lt;br /&gt;        btn1Text: &lt;span class=&quot;st0&quot;&gt;&#39;Button 1&#39;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;co1&quot;&gt;// public methods&lt;/span&gt;&lt;br /&gt;        init: &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;Ext.&lt;span class=&quot;me1&quot;&gt;Ext2&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                btn1 = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                    renderTo: &lt;span class=&quot;st0&quot;&gt;&#39;btn1-ct&#39;&lt;/span&gt;,&lt;br /&gt;                    text: &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;btn1Text&lt;/span&gt;,&lt;br /&gt;                    handler: btn1Handler&lt;br /&gt;                &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;            &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;kw1&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                btn1 = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;btn1-ct&#39;&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                    text: &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;btn1Text&lt;/span&gt;,&lt;br /&gt;                    handler: btn1Handler&lt;br /&gt;                &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;            &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;; &lt;span class=&quot;co1&quot;&gt;// end of app&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// end of file&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Переменные btn1 и privVar1 - закрытые, private. Это значит что к ним можно получить доступ только из приложения а вне его они невидимы. Тоже самое справедливо для частной функции btn1Handler.&lt;br /&gt;С другой стороны, btn1Text это публичная public переменная которая видима и может быть доступна или изменена извне приложения (мы продемонстрируем это позже).&lt;br /&gt;Функция init  привелигирована в том что может работать как с public так и с private переменными и функциями. В нашем примере она работает с публичной переменной this.btn1Text, а также с private функцией btn1Handler. Функция init публичная (public) и может быть вызвана откуда угодно.&lt;br /&gt;Ок, давайте запустим его. Видите кнопку в верхнем левом углу? Хорошо. Нажмите ее. Вы получите сообщение privVar1=11, так? Частная private функция может работать с частными private переменными.&lt;br /&gt;Однако что то не так при втором показе сообщения и мы видим что this.btn1Text=undefined; это не то, что мы ожидали. Причина в том, что переменная this внутри обработчика теперь указывает на кнопку а не на наше приложение. Добавьте scope:this в конфигурацию кнопки вот так:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;Ext.&lt;span class=&quot;me1&quot;&gt;Ext2&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    btn1 = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        renderTo: &lt;span class=&quot;st0&quot;&gt;&#39;btn1-ct&#39;&lt;/span&gt;,&lt;br /&gt;        text: &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;btn1Text&lt;/span&gt;,&lt;br /&gt;        handler: btn1Handler,&lt;br /&gt;        scope:&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;kw1&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    btn1 = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;btn1-ct&#39;&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        text: &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;btn1Text&lt;/span&gt;,&lt;br /&gt;        handler: btn1Handler,&lt;br /&gt;        scope:&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;и перезагрузите страницу. Работает теперь?&lt;br /&gt;&lt;br /&gt;Перезагрузка (перекрытие) публичных переменных.&lt;br /&gt;Добавьте следующий код в конце applayout.js чтобы было так: &lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;Ext.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;myNameSpace.&lt;span class=&quot;me1&quot;&gt;app&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    btn1Text:&lt;span class=&quot;st0&quot;&gt;&#39;Taste 1&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// end of file&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Что теперь делает весь этот код? Сначала он создает объект нашего приложения и затем изменяет (перезагружает) значение публичной переменной btn1Text. Запустите его, чтобы увидеть что текст на кнопке изменился.&lt;br /&gt;Хорошая практика кодирования это хранить весь текст используемый приложением в публичных переменных, так они могут быть легко переведены на другие языки без изменения оригинального кода приложения.&lt;br /&gt;Конечно, следует хранить также другие значения, такие как размеры по-умолчанию, стили и другие настраиваемые опции в публичных переменных. Тогда вам не понадобится исследовать тысячи строк кода приложения чтобы изменить цвет какого нибудь элемента например.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Перегрузка (перекрытие) публичных функций&lt;br /&gt; &lt;br /&gt;Давайте изменим наш код на следующий:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;Ext.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;myNameSpace.&lt;span class=&quot;me1&quot;&gt;app&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    btn1Text:&lt;span class=&quot;st0&quot;&gt;&#39;Taste 1&#39;&lt;/span&gt;,&lt;br /&gt;    init: &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;kw1&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            btn1 = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;btn1-ct&#39;&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                text: &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;btn1Text&lt;/span&gt;,&lt;br /&gt;                handler: btn1Handler,&lt;br /&gt;                scope: &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;        &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;kw1&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kw3&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;Error: &quot;&#39;&lt;/span&gt; + e.&lt;span class=&quot;me1&quot;&gt;message&lt;/span&gt; + &lt;span class=&quot;st0&quot;&gt;&#39;&quot; at line: &#39;&lt;/span&gt; + e.&lt;span class=&quot;me1&quot;&gt;lineNumber&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;        &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// end of file&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Что мы здесь сделали? Просто переопределили функцию init тем же кодом что и до того, только заключенным в блок try/catch чтобы мы могли обрабатывать любые ошибки. Должны мы ожидать прежнего результата или другого? Запустите и увидите.&lt;br /&gt;Да, будет ошибка о том что btn1Handler не определен. Это потому, что обновленная функция пытается получить доступ к частной переменной но не может. Вы видите, оригинальный init привелоигирован и имеет доступ к частному пространству но новый не имеет. В этом есть аспект безопасности: Никакой внешний код не должен получать доступ к частному пространству даже если пытается перегрузить привелигированные методы.</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/8650832292704308964/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2009/01/extjs.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/8650832292704308964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/8650832292704308964'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2009/01/extjs.html' title='Приложения в ExtJS'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-5181071970187669970</id><published>2008-12-15T10:19:00.003+02:00</published><updated>2008-12-15T10:40:08.471+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Учебник: работа с данными в Ext"/><title type='text'>Учебник: работа с данными в Ext</title><content type='html'>Основная концепция данных&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;- Stores&lt;/span&gt; - Store это хранилище данных для таблиц (Grid). Это кэш объектов Ext.data.Record, который содержит те поля, которые вы указываете. Поля могут быть доступны по имени.&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;-Proxies&lt;/span&gt; - Хранилище Store использует объект Proxy для получения данных из заданного их месторасположения. Если у вас допустим просто javascript массив прямо в коде страницы, то вам понадобиться MemoryProxy, конструктор которого просто работает с этими данными. Если вы получаете данные с сервера, расположенного в том же домене, то вам нужен HttpProxy. Proxy достаточно прозрачен. Он всего лишь обеспечивает доступ к порциям данных. Вы назначаете объект Reader взависимости от того, какие данные ожидаются. Вам лучше использовать ArrayReader если у вас просто MemoryProxy, который рабоает с со значениями массивов.&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;-Readers &lt;/span&gt;- Reader, является конструктором для определения данных, как бы расставляя поля. Он выделяет отдельные поля из порции данных и передает их массиву записей, которые передаются в хранилище с помощью метода loadRecords, который и обновляет кэш хранилища.&lt;br /&gt;&lt;br /&gt;Основные классы данных&lt;br /&gt;-Ext.data.Connection - класс обеспечивает подключение к соответствующему домену страницы, позволяя делать запросы как к статическому URL, так и к динамическому, указанному в процессе запроса.&lt;br /&gt;-Ext.data.Record - экземпляры этого класса одновременно и определяют описание информации и описание для использования информации записей в  хранилище Ext.data.Store или любом другом коде которому нужно иметь доступ к записям, сохраненным в Ext.data.Store объекте.&lt;br /&gt;-Ext.data.SortTypes - Этот класс является уникальным и не может быть создан напрямую.&lt;br /&gt;-Ext.data.Tree -Представляет структуру дерева данных и все события узлов дерева. &lt;br /&gt;-Ext.data.Node -не указано&lt;br /&gt;&lt;br /&gt;Источник: &lt;a href=&quot;http://extjs.com/learn/Manual:Data&quot;&gt;http://extjs.com/learn/Manual:Data&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/5181071970187669970/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/ext_15.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/5181071970187669970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/5181071970187669970'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/ext_15.html' title='Учебник: работа с данными в Ext'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-6379453818257790059</id><published>2008-12-10T11:28:00.001+02:00</published><updated>2008-12-10T11:29:52.298+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Расширение Ext для новичков"/><title type='text'>Расширение Ext для новичков</title><content type='html'>Источник:&lt;a href=&quot;http://extjs.com/learn/Tutorial:Extending_Ext_for_Newbies&quot;&gt; http://extjs.com/learn/Tutorial:Extending_Ext_for_Newbies&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Обычно вы хотите привнести мощь объектно-ориентированного проектирования с помощью классов. Вы делаете это по нескольким причинам как объяснено в этом учебнике.&lt;br /&gt;&lt;br /&gt;Классы, используемые многократно&lt;br /&gt;&lt;br /&gt;Иногда вам нужны будут компоненты, конфигурационные опции которых вы хотите использовать многократно. Например, у вас может быть набор панелей с одной и той же шириной и высотой, но с разными заголовками. Это назывется предопределенные (предварительно-сконфигурированные) классы.&lt;br /&gt;&lt;br /&gt;Модель Конструктора&lt;br /&gt;&lt;br /&gt;Один вариант решения это использование функции конструктора, как например здесь:&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;co1&quot;&gt;// функция - конструктор&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; MyPanel = &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Ext.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt; &lt;br /&gt;        &lt;span class=&quot;co1&quot;&gt;// создайте нужные опции здесь&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        width: &lt;span class=&quot;nu0&quot;&gt;300&lt;/span&gt;,&lt;br /&gt;        height: &lt;span class=&quot;nu0&quot;&gt;300&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;    MyPanel.&lt;span class=&quot;me1&quot;&gt;superclass&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;constructor&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;, arguments&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// MyPanel расширяет возможности Ext.Panel&lt;/span&gt;&lt;br /&gt;Ext.&lt;span class=&quot;me1&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;MyPanel, Ext.&lt;span class=&quot;me1&quot;&gt;Panel&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; myfirstpanel = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; MyPanel&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    title: &lt;span class=&quot;st0&quot;&gt;&#39;My First Panel&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; mysecondpanel = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; MyPanel&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    title: &lt;span class=&quot;st0&quot;&gt;&#39;My Second Panel&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Фабрика шаблонов (палитр)&lt;br /&gt;Другой путь для создания предопределенных объектов это использование фабрики шаблонов дизайна. Фабричная функция (предопределенная функция) возвращает новый экземпляр объекта. Этот подход не требует расширения классов (краткий обзор не позволяет обсудить это подробно). Фабрика шаблонов это альтернативный вышеупомянутому метод который особенно полезен когда все, что вы хотите сделать, это задать конфигурирование свойств &quot;по-умолчанию&quot;, не расширяя/переопрделяя базовый класс.&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt; createMyPanel&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;Panel&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;Ext.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;co1&quot;&gt;//опции по-умолчанию идут здесь&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        width: &lt;span class=&quot;nu0&quot;&gt;300&lt;/span&gt;,&lt;br /&gt;        height: &lt;span class=&quot;nu0&quot;&gt;300&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;, config&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; myfirstpanel = createMyPanel&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    title: &lt;span class=&quot;st0&quot;&gt;&#39;My First Panel&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; mysecondpanel = createMyPanel&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    title: &lt;span class=&quot;st0&quot;&gt;&#39;My Second Panel&#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Расширение функциональности&lt;br /&gt;&lt;br /&gt;Другая причина, по которой вы хотите использовать ОО классы это когда вы хотите расширить функциональность другого класса. Допустим вы хотите добавить функцию в вышеупомянутую панель и переопределить существующую функцию. Есть один путь сделать это:&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;co1&quot;&gt;// Конструктор&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; MyPanel = &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;//Повторно-используемые опции идут здесь&lt;/span&gt;&lt;br /&gt;    Ext.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        width: &lt;span class=&quot;nu0&quot;&gt;300&lt;/span&gt;,&lt;br /&gt;        height: &lt;span class=&quot;nu0&quot;&gt;300&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// вызов конструктора суперкласса для сохранения функциональности класса-родителя&lt;/span&gt;&lt;br /&gt;    MyPanel.&lt;span class=&quot;me1&quot;&gt;superclass&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;constructor&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;, arguments&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// Здесь вы можете добавить функциональность, нужную вам, &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;//например обработку событий. &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;click&#39;&lt;/span&gt;, &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;kw3&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&quot;You Clicked &quot;&lt;/span&gt; + &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;, &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// MyPanel расширяет Ext.Panel&lt;/span&gt;&lt;br /&gt;Ext.&lt;span class=&quot;me1&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;MyPanel, Ext.&lt;span class=&quot;me1&quot;&gt;Panel&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// Здесь вы можете добавить статические переменные класса, переменные, которые будут иметь &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;//одинаковое значение для всех объектов класса.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// Если вы не уверены нужно ли включать его в конструктор выше. Не помещайте никакого объекта&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// созданного с помощью &#39;new&#39; или &#39;xtype&#39; здесь. Безопаснее положить его в конфигурационных&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// опциях в конструкторе.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// Новая функция добавлена&lt;/span&gt;&lt;br /&gt;    myNewFunction: &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;,&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// Переопределить существующую функцию&lt;/span&gt;&lt;br /&gt;    onRender: &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        MyPanel.&lt;span class=&quot;me1&quot;&gt;superclass&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;onRender&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;, arguments&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;        &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;myNewFunction&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; myfirstpanel = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; MyPanel&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    title: &lt;span class=&quot;st0&quot;&gt;&#39;My First Panel&#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; mysecondpanel = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; MyPanel&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    title: &lt;span class=&quot;st0&quot;&gt;&#39;My Second Panel&#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;Другой путь для создания конструктора выше показан @Condor :&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; MyPanel = &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// вызов конструктора суперкласса для сохранения функциональности класса-родителя&lt;/span&gt;&lt;br /&gt;    MyPanel.&lt;span class=&quot;me1&quot;&gt;superclass&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;constructor&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;, Ext.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;co1&quot;&gt;//опции по-умолчанию идут здесь&lt;/span&gt;&lt;br /&gt;        width: &lt;span class=&quot;nu0&quot;&gt;300&lt;/span&gt;,&lt;br /&gt;        height: &lt;span class=&quot;nu0&quot;&gt;300&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;, config&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// После конструктора суперкласса добавьте требуемую функциональность&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;//для объекта (обработка событий, прослушивание)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;click&#39;&lt;/span&gt;, &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;kw3&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&quot;You Clicked &quot;&lt;/span&gt; + &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;, &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Вышеупомянутый способ расширения Ext класса это модель конструктора. Другой путь расширения Ext класса - использование initComponent, один из шаблонных методов Ext JS созданный  специально для этого. Как вы можете догадаться этот метод применяется только для расширения Ext компонентов. Вот пример использования:&lt;br /&gt;var MyPanel = Ext.extend(Ext.Panel, {&lt;br /&gt;    // Здесь добавляются статические переменные &lt;br /&gt;    // &lt;br /&gt;    // If you are not sure put it in the constructor above. Do not  put&lt;br /&gt;    // any object created with &#39;new&#39; or &#39;xtype&#39; here. It is safer to &lt;br /&gt;    // put it in the config option of the constructor.&lt;br /&gt; &lt;br /&gt;    // New function added&lt;br /&gt;    initComponent: function() {&lt;br /&gt;        //Reusable config options here&lt;br /&gt;        Ext.apply(this,&lt;br /&gt;            width: 300,&lt;br /&gt;            height: 300&lt;br /&gt;        });&lt;br /&gt;       // And Call the superclass to preserve baseclass functionality&lt;br /&gt;       MyPanel.superclass.initComponent.apply(this, arguments);&lt;br /&gt;        // Here you can add functionality that requires the object to&lt;br /&gt;        // exist, like event handling.&lt;br /&gt;        this.on(&lt;br /&gt;            &#39;click&#39;,&lt;br /&gt;            function() {&lt;br /&gt;                alert(&quot;You Clicked &quot; + this.title);&lt;br /&gt;            },&lt;br /&gt;            this&lt;br /&gt;        );&lt;br /&gt;    },&lt;br /&gt;    myNewFunction: function() {&lt;br /&gt;    },&lt;br /&gt;    // Override an existing function&lt;br /&gt;    onRender: function() {&lt;br /&gt;        MyPanel.superclass.onRender.apply(this, arguments);&lt;br /&gt;        this.myNewFunction();&lt;br /&gt;    }&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;Первое что вы получите это оповещение, что нет конструктора. Ext создает конструктор сам. Конструктор создается Ext с помощью вызова initComponent. Это широко используемый метод, который вы найдете в продвинутых учебниках и примерах. Но запомните сейчас, что он делает тоже самое, что и модель конструктора.&lt;br /&gt;&lt;br /&gt;Предпочитаемый путь для обработки событий (listeners) это добавить их после вызова суперкласса в конструктор или initComponent.&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;MyPanel.&lt;span class=&quot;me1&quot;&gt;superclass&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;constructor&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;, arguments&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// Here you can add functionality that requires the object to exist, &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// like event handling. &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;st0&quot;&gt;&#39;click&#39;&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kw3&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&quot;You Clicked &quot;&lt;/span&gt; + &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;        &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;В случае фабричного метода можно добавить обработчки событий вне фабричного метода, как здесь:&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;myFirstPanel.&lt;span class=&quot;me1&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;st0&quot;&gt;&#39;click&#39;&lt;/span&gt;,&lt;br /&gt;        &lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kw3&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&quot;You Clicked &quot;&lt;/span&gt; + &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;        &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;,&lt;br /&gt;        myFirstPanel &lt;span class=&quot;co1&quot;&gt;//scope&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Есть и другие пути обработки событий. Но они более для продвинутых пользователей</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/6379453818257790059/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/ext_10.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6379453818257790059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6379453818257790059'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/ext_10.html' title='Расширение Ext для новичков'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-1624997226675021365</id><published>2008-12-09T10:26:00.002+02:00</published><updated>2008-12-09T10:28:22.277+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><title type='text'>Проектирование больших приложений в Ext</title><content type='html'>Вступление&lt;br /&gt;&lt;br /&gt;Я решил написать эту статью для тех пользователей Ext2.x которые уже выросли из детских потребностей, создавая одну HTML страницу c простыми скриптами которые создают одно простое окно или форму, для тех кто уже решил что Ext - это путь, и для тех кто борется со слишком большими файлами, трудными для поиска и чувствующих, что их приложениям нужна структура.&lt;br /&gt;&lt;br /&gt;Количество проблем и путей их решения равно количеству людей, работающих над этим. Способ, который я опишу в тексте, не единственный, и я не хочу сказать что приложение можно написать только моим способом, иначе будет неверно. Ничего подобного.&lt;br /&gt;&lt;br /&gt;Все что я хочу сказать, то что этот вариант рабочий, достаточно структурированный, легко разрабатываемый - просто сказать - Он работает!&lt;br /&gt;&lt;br /&gt;Что такое Большое приложение?&lt;br /&gt;&lt;br /&gt;Если вы сделали Viewport  с BorderLayout, таблицой и формой и все это находится в одном файле - это большое приложение, не так ли? Если вы создали десяток окон с таблицами, формами или границами - это большое приложение, да?&lt;br /&gt;&lt;br /&gt;У немцев есть отличные слова: Jein - комбинация слов Да и Нет.&lt;br /&gt;Ответ для обоих вариантов - Jein (и да и нет). Когда приложение становится большим? Ответ простой: оно становится большим когда вы чувствуете, что оно большое. Это начинается тогда, когда у вас у самих начинаются проблемы в ориентировании в множестве файлов или вы не можете найти нужный код в одном файле., когда вы уже не понимаете взаимосвязь компонентов и так далее. Я это пишу, но представьте когда у программиста с в 2-3 раза большим опытом появляется это чувство?&lt;br /&gt;Мы может просто установить, что каждое приложение становится большим, когда оно хорошо написано и у нас не вызовет проблем добавиьт в него дополнительные возможности, дописать новый код, новые CSS правила и так далее.&lt;br /&gt;Лучший и безопасный вариант старта нового приложения это чувство : я начинаю большое приложение!&lt;br /&gt;&lt;br /&gt;Файлы и директории&lt;br /&gt;Это первое что нам нужно организовать. Всегда существует корневая директория DocumentRoot на Apache или другом HTTP сервере, так что все поддиректории которые я опишу позже расположены относительно нее.&lt;br /&gt;Рекомендуемая структура директорий такова:&lt;br /&gt;&lt;pre class=&quot;source source-bash&quot;&gt;./css &lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;optionally link&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;&lt;br /&gt;./ext &lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;ссылка&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;&lt;br /&gt;./img &lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;ссылка&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;&lt;br /&gt;./js&lt;br /&gt;index.html&lt;/pre&gt;&lt;br /&gt;Ссылка в вышеупомянутой структуре означает мягкую ссылку, указывающую на реальное месторасположение файлов. Это нужно для того, когда вы например, скачаете новую версию Ext в директорию, то просто измените ссылку на нее, без изменений кода, ссылающегося на нее и можете испытать что все работает правильно в новой версии. Если да, можно оставить все как есть, если нет, просто изменить ссылку на прежнюю.&lt;br /&gt;&lt;br /&gt;    * css содержит все таблицы стилей. Если у вас есть глобальные стили с цветами компании или шрифтами вы можете создать и эту директорию как ссылку.&lt;br /&gt;    * ext ссылается на библиотеку Ext JS как было описано выше&lt;br /&gt;    * img ссылается на ваши изображения. Также она может иметь поддиректорию с иконками.&lt;br /&gt;    * js будет содержать все JavaScript файлы приложения.&lt;br /&gt;    * index.html HTML файл, который является стартовой точкой приложения. Вы можете назвать его как захотите и можете добавить другие файлы, например файлы для процесса аутентификации. В любом случает должна быть одна стартовая точка - файл.&lt;br /&gt;    * опционально вы можете создать директорию или ссылку на серверную часть приложения (у меня например ./classes). Вы можете называть их как пожелаете, но придерживаться целостности для приложений, которые пишите (./server, ./php хорошие примеры)&lt;br /&gt;&lt;br /&gt;index.html&lt;br /&gt;&lt;br /&gt;Самое минимальное содержание файла index.html такое&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;source source-html4strict&quot;&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;http-equiv&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;content&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/html; charset=utf-8&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;rel&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/css&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;./ext/resources/css/ext-all.css&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;rel&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/css&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;./css/application.css&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;script&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;./ext/adapter/ext/ext-base.js&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;script&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;./ext/ext-all-debug.js&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;script&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; &lt;span class=&quot;kw3&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&quot;./js/application.js&quot;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;/span&gt;A Big Application&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;sc2&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Чтобы я рекомендовал сделать в файле выше, добавить описательный заголовок не только в этот файл но и во все создаваемые файлы. Также маркер End of file имеет значение. Смотрите File Patterns как пример таких заголовков.&lt;br /&gt;&lt;br /&gt;js/application.js&lt;br /&gt;&lt;br /&gt;Нам нужен файл, где будет располагаться функция onReady, давайте назовем его application.js. Его минимальное содержимое такое:&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;co1&quot;&gt;// vim: sw=4:ts=4:nu:nospell:fdc=4&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;coMULTI&quot;&gt;/**&lt;br /&gt; * An Application&lt;br /&gt; *&lt;br /&gt; * @author    Ing. Jozef Sakáloš&lt;br /&gt; * @copyright (c) 2008, by Ing. Jozef Sakáloš&lt;br /&gt; * @date      2. April 2008&lt;br /&gt; * @version   $Id$&lt;br /&gt; *&lt;br /&gt; * @license application.js is licensed under the terms of the Open Source&lt;br /&gt; * LGPL 3.0 license. Commercial use is permitted to the extent that the &lt;br /&gt; * code/component(s) do NOT become part of another Open Source or Commercially&lt;br /&gt; * licensed development library or toolkit without explicit permission.&lt;br /&gt; * &lt;br /&gt; * License details: http://www.gnu.org/licenses/lgpl.html&lt;br /&gt; */&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;coMULTI&quot;&gt;/*global Ext, Application */&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;Ext.&lt;span class=&quot;me1&quot;&gt;BLANK_IMAGE_URL&lt;/span&gt; = &lt;span class=&quot;st0&quot;&gt;&#39;./ext/resources/images/default/s.gif&#39;&lt;/span&gt;;&lt;br /&gt;Ext.&lt;span class=&quot;me1&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;Application&#39;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// application main entry point&lt;/span&gt;&lt;br /&gt;Ext.&lt;span class=&quot;me1&quot;&gt;onReady&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    Ext.&lt;span class=&quot;me1&quot;&gt;QuickTips&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span class=&quot;co1&quot;&gt;// code here&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;; &lt;span class=&quot;co1&quot;&gt;// eo function onReady&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span class=&quot;co1&quot;&gt;// eof&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ваш заголовок и подвал может изменяться но удостоверьтесь что установили Ext.BLANK_IMAGE_URL на ваш сервер. Это путь на прозрачное изображение 1х1 пикселей которое используется Ext как указатель расположения ихображения, и если он указывает на неверное месторасположение вы можете получить проблемы при отрисовке, такие как потеря изображений в элементах, отсутствие иконок или что-то подобное.&lt;br /&gt;Вам может также понадобится новой глобальной переменной объекта для приложения ( здесь это Application).&lt;br /&gt;В чем вы должны быть уверены то что Ext.onReady это главная начальная точка приложения.&lt;br /&gt;&lt;br /&gt; css/application.css&lt;br /&gt;&lt;br /&gt;Здесь будут храниться ваши таблицы стилей, в этом файле. Если вам нужно всего лишь пару правил, то создавать отдельный файл нет необходимости, и будет лучше просто включить его в заголовок страницы.&lt;br /&gt;Обратное тоже истина, помните, вы пишите большое приложение, поэтому все должно быть на своем месте. Если вы напишите таблицу стилей прямо в заголовке файла, то рано или поздно у вас могут возникнуть проблемы при отображении и вы забудете где вы сохранили эти стили.&lt;br /&gt;&lt;br /&gt;Ошибочный путь&lt;br /&gt;&lt;br /&gt;Что обычно следует когда мы начинаем создавать что то? Давайте напишем. Итак, мы сидим и начинаем писать:&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; vp = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;Viewport&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     layout:&lt;span class=&quot;st0&quot;&gt;&#39;border&#39;&lt;/span&gt;&lt;br /&gt;    ,items:&lt;span class=&quot;br0&quot;&gt;[&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;grid&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;GridPanel&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            store:&lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;data&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;Store&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                 proxy:&lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;data&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;HttpProxy&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt; ...&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Подождите минутку. С таким подходом у нас будет 10000 строк в нашем application.js очень скоро и это то, чего мы хотим в последнюю очередь. Очевидно, мы пропустили какой-то шаг, как будто мы не могли написать это все сразу в index.html?&lt;br /&gt;&lt;br /&gt;Правильный путь: Разбиваем все на части&lt;br /&gt;&lt;br /&gt;Даже самое сложное состоит из маленьких подсистем, а те состоят из еще более мелких частей, которые тоже состоят из каких-либо элементов. И при написании больших приложений нет исключения. Теперь настало время определить эти части, компоненты и взаимосвязи между ними.&lt;br /&gt;&lt;br /&gt;Итак, сядьте, обдумайте все, набросайте схему, сделайте список, но в результате вы должны знать компоненты - хотя бы самые основные, из которых состоит ваше приложение.&lt;br /&gt;&lt;br /&gt;Предопределенные классы&lt;br /&gt;&lt;br /&gt;Теперь, когда вы проанализировали приложение и определили его компоненты вы можете начать писать. Но как? Самый лучший подход - написать расширение для классов Ext компонент, у которых есть все конфигурационные опции, или они передаются встроенными в конфигурационный объект. Я использую такие предопределенные классы расширения так как они удобнее и более функциональны чем базовые Ext классы, но их главное назначение - это их настройка для своих нужд. Например, чтобы создать таблицу Персонал со специфичной моделью колонок, хранилищем, опциями сортировки, редакторами и тд.&lt;br /&gt;Если у нас такой подход, наше конфигурационное Окно могло мы выглядеть так:&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; win = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;Window&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     title:&lt;span class=&quot;st0&quot;&gt;&#39;Personnel&#39;&lt;/span&gt;&lt;br /&gt;    ,width:&lt;span class=&quot;nu0&quot;&gt;600&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    ,height:&lt;span class=&quot;nu0&quot;&gt;400&lt;/span&gt;&lt;br /&gt;    ,items:&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;xtype:&lt;span class=&quot;st0&quot;&gt;&#39;personnelgrid&#39;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;win.&lt;span class=&quot;me1&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Создание предопределенных классов.&lt;br /&gt;&lt;br /&gt;(Запомните: Следующая структура может работать не во всех ситуациях, есть исключения)&lt;br /&gt;&lt;br /&gt;Давайте обсудим один пример:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;Application.&lt;span class=&quot;me1&quot;&gt;PersonnelGrid&lt;/span&gt; = Ext.&lt;span class=&quot;me1&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;Ext.&lt;span class=&quot;me1&quot;&gt;grid&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;GridPanel&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     border:&lt;span class=&quot;kw2&quot;&gt;false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    ,initComponent:&lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        Ext.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;             store:&lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;data&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;Store&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            ,columns:&lt;span class=&quot;br0&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;, &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;]&lt;/span&gt;&lt;br /&gt;            ,plugins:&lt;span class=&quot;br0&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;br0&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            ,viewConfig:&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;forceFit:&lt;span class=&quot;kw2&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;            ,tbar:&lt;span class=&quot;br0&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;br0&quot;&gt;]&lt;/span&gt;&lt;br /&gt;            ,bbar:&lt;span class=&quot;br0&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;br0&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        Application.&lt;span class=&quot;me1&quot;&gt;PersonnelGrid&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;superclass&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;initComponent&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;, arguments&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// eo function initComponent&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    ,onRender:&lt;span class=&quot;kw2&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;store&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;        Application.&lt;span class=&quot;me1&quot;&gt;PersonnelGrid&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;superclass&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;onRender&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kw1&quot;&gt;this&lt;/span&gt;, arguments&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;    &lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// eo function onRender&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;Ext.&lt;span class=&quot;me1&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&#39;personnelgrid&#39;&lt;/span&gt;, Application.&lt;span class=&quot;me1&quot;&gt;PersonnelGrid&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Что мы здесь делаем? Мы расширяем класс Ext.grid.GridPanel создавая новый класс (расширение) Application.PersonelGrid и мы регистрируем его как новый xtype с именем personnelgrid.&lt;br /&gt;Мы передаем главноей табличной панели все конфигурационные опции необходимые для специфичной таблицы персонала. С этой точки у нас есть новый компонент, строительный блок для нашего приложения, который мы сможем использовать где-либо (окна, регион, отдельно-стоящий) где нам понадобится список персонала. Мы можем создать его так:&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; pg = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Application.&lt;span class=&quot;me1&quot;&gt;PersonnelGrid&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;или с помощью xtype (для ленивых)&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;var&lt;/span&gt; win = &lt;span class=&quot;kw2&quot;&gt;new&lt;/span&gt; Ext.&lt;span class=&quot;me1&quot;&gt;Window&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     items:&lt;span class=&quot;br0&quot;&gt;{&lt;/span&gt;xtype:&lt;span class=&quot;st0&quot;&gt;&#39;personnelgrid&#39;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    ,....&lt;br /&gt;&lt;span class=&quot;br0&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Организация предопределенных классов&lt;br /&gt;&lt;br /&gt;Код выше не должен и не нужно запускать его внутри функции onReady, потому что он ничего не делает с DOM структурой документа; он только создает JavaScript объект. Вот почему он может и должен быть написан в отдельном файле (js/Application.PersonnelGrid.js) и он может и должен быть включен в заголовок index.html файла как:&lt;br /&gt;&lt;pre class=&quot;source source-javascript&quot;&gt;&amp;lt;script type=&lt;span class=&quot;st0&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; src=&lt;span class=&quot;st0&quot;&gt;&quot;./js/Application.PersonnelGrid.js&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Шаг за шагом мы продолжаем создавать наши предопределенные классы, складывать их в /js директорию, включать их в index.html и строить наше приложение из них, как пазл, собирая из кусочков.&lt;br /&gt;Выглядит хорошо, так?&lt;br /&gt;&lt;br /&gt;В любом случае, есть еще что добавить.&lt;br /&gt;&lt;br /&gt;Межкомпонентное взаимодействие&lt;br /&gt;&lt;br /&gt;Представьте что нам нужен экран с каймой со списком ссылок на западе и таб-панелью в центре. Нажатие ссылки в списке должно создавать новую закладку в центре. Теперь, куда мы должны положить логику этого события и процедуру обработки? На запад или в центр?&lt;br /&gt;Ни в одно из них. Почему? Если у нас есть предопределенные классы которые создают и показывают ссылки на западе (слева) и мы положили всю логику в них, то они больше не могут существовать без центрального региона. Мы можем просто не сможем их использовать без центра, так как не сможем создавать закладки в центре.&lt;br /&gt;Если положить логику в центр - результат будет тот же: центр не сможет существовать без запада.&lt;br /&gt;Единственный компонент, который будет независим в этом случае это их контейнер - border layout, и это единственно правильное место куда следует поместить межкомпонентную связь.&lt;br /&gt;Что мы затем должны сделать? Контейнер (с border layout) должен прослушивать все события с запада и должен создавать закладки в центре как ответ на эти клики. Пример такого межкомпонентного взаимодействия можно найти по ссылке http://examples.extjs.eu/?ex=compcomm&lt;br /&gt;&lt;br /&gt;Система представлений&lt;br /&gt;&lt;br /&gt;По мере создания приложения число файлов растет, число включений JavaScript файлов тоже (у меня в одном приложении включается около 80 файлов и их количество каждый день растет). Это може уменьшить производительность и продуктивность системы.&lt;br /&gt;Лучший путь решения - это слияние всех javascript файлов и создание одного большого файла, и минимизирование его с помощью JavaScript или других инструментов сжатия. Также вам не понадобится отладка библиотеки Ext для готовой системы.&lt;br /&gt;&lt;br /&gt;На продуктивной системе нам надо включить:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;ext-all.js&lt;/li&gt;&lt;br /&gt;&lt;li&gt;app-all.js and&lt;/li&gt;&lt;br /&gt;&lt;li&gt;application.js&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Для дополнительной информации о минимизации исходных кодов и создания комбинированных файлов у нас есть другой учебник, который раскрывает эту тему более подробно (http://extjs.com/learn/Tutorial:Building_Ext_From_Source).&lt;br /&gt;&lt;br /&gt;Заключение&lt;br /&gt;Вот и все почти... Есть специфичные техники для специальных Ext классов, есть множество других ноу-хау сервер-клиентских приложений, но выше изложена практически основная концепция.&lt;br /&gt;Удачного кодинга!&lt;br /&gt;&lt;br /&gt;Источник: &lt;a href=&quot;http://extjs.com/learn/Tutorial:Writing_a_Big_Application_in_Ext&quot;&gt;http://extjs.com/learn/Tutorial:Writing_a_Big_Application_in_Ext&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/1624997226675021365/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/ext.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1624997226675021365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1624997226675021365'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/ext.html' title='Проектирование больших приложений в Ext'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-6965954452949022952</id><published>2008-12-08T11:10:00.002+02:00</published><updated>2008-12-09T10:30:07.212+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Таблицы PHP SQL"/><title type='text'>Учебник: Grid PHP SQL Часть 12</title><content type='html'>Создание контекстного меню (правой кнопки)&lt;br /&gt;&lt;br /&gt;Это будет последняя часть учебника!!! Знаю, знаю... было очень весело читать! Ок, достаточно! Теперь мы поговорим о контекстных меню или как их обычно называют меню открывающиеся по правому клику мышки.&lt;br /&gt;&lt;br /&gt;Во-первых мы записываем номер ряда, на котором мы нажали:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var PresidentListingSelectedRow;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;У нас будет простое меню с тремя пунктами: изменение текущей записи, удаление и печать таблицы.&lt;br /&gt;Ок, давайте определим четыре функции. Первая будет вызываться каждый раз при нажатии правой кнопки мыши на таблице:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  function onPresidentListingEditorGridContextMenu(grid, rowIndex, e) {&lt;br /&gt;    e.stopEvent();&lt;br /&gt;    var coords = e.getXY();&lt;br /&gt;    PresidentListingContextMenu.rowRecord = grid.store.getAt(rowIndex);&lt;br /&gt;    grid.selModel.selectRow(rowIndex);&lt;br /&gt;    PresidentListingSelectedRow=rowIndex;&lt;br /&gt;    PresidentListingContextMenu.showAt([coords[0], coords[1]]);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ок, как вы видите мы показываем переменную названную PresidentListingContextMenu. Мы ее еще не создали, мы сделаем это сразу после этого. Давайте определим три функции которые будут вызываться для каждого пункта меню:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  function modifyPresidentContextMenu(){&lt;br /&gt;      PresidentListingEditorGrid.startEditing(PresidentListingSelectedRow,1);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  function deletePresidentContextMenu(){&lt;br /&gt;      confirmDeletePresidents();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  function printListingContextMenu(){&lt;br /&gt;      printListing();&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Как видите, это те функции, которые мы уже определили. Ок, давайте определим ContextMenu:&lt;br /&gt;&lt;pre&gt;  PresidentListingContextMenu = new Ext.menu.Menu({&lt;br /&gt;      id: &#39;PresidentListingEditorGridContextMenu&#39;,&lt;br /&gt;      items: [&lt;br /&gt;      { text: &#39;Modify this President&#39;, handler: modifyPresidentContextMenu },&lt;br /&gt;      { text: &#39;Delete this President&#39;, handler: deletePresidentContextMenu },&lt;br /&gt;      &#39;-&#39;,&lt;br /&gt;      { text: &#39;Print this grid&#39;, handler: printListingContextMenu }&lt;br /&gt;      ]&lt;br /&gt;   }); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Последнее, что нам понадобится это перехватчик событий (actionlistener) который будет вызывать функцию onPresidentListingEditorGridContextMenu при нажатии правой кнопки (я пытался найти еще более длинное имя для этой функции, но... :))&lt;br /&gt;&lt;pre&gt;  PresidentListingEditorGrid.addListener(&#39;rowcontextmenu&#39;, onPresidentListingEditorGridContextMenu);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Это конец учебника. Надеюсь он помог вам понять как работать с таблицами в ext. Теперь вы понимаете ее код. Не забывайте проверять наши материалы и играйте с различными методами, свойствами и событиями.&lt;br /&gt;&lt;br /&gt;Вы можете оставить отзыв на форуме http://extjs.com/forum/showthread.php?p=144865#post144865&lt;br /&gt;For more advanced features and usage of grids, I want to once again refer you to Michael Lecomte&#39;s tutorial.&lt;br /&gt;Для более продвинутых функций таблиц посмотрите учебник Michael Lecomte&#39;s &lt;br /&gt;Happy Griding!http://extjs.com/learn/Tutorial:Ext20_Grid_Editor_PHP_MySQL&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Nicolas Bize. &lt;br /&gt;&lt;br /&gt;Что запомнить из этой части&lt;br /&gt;&lt;br /&gt;    *  Перехватчик событий необходимо прикреплять к таблице&lt;br /&gt;    * Вам не надо пересоздавать контекстное меню каждый раз заново, так как это глобальная переменная :)&lt;br /&gt;&lt;br /&gt;Материалы этой части можно скачать по ссылке http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%2012.zip</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/6965954452949022952/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-12.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6965954452949022952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6965954452949022952'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-12.html' title='Учебник: Grid PHP SQL Часть 12'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-2012358788417021807</id><published>2008-12-08T11:09:00.000+02:00</published><updated>2008-12-09T10:30:07.212+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Таблицы PHP SQL"/><title type='text'>Учебник: Grid PHP SQL Часть 11</title><content type='html'>Печать вашей таблицы.&lt;br /&gt;&lt;br /&gt;Отлично... Я собираюсь сказать одну вещь до того, как буду заспамлен тоннами писем с критикой... Метод, описанный здесь для печати вашей таблицы не единственно возможный и не самый оригинальный. Это просто быстрый пример того, как можно распечатать таблицу.&lt;br /&gt;&lt;br /&gt;Наш метод - это просто создание HTML файла и заполнение его массивом, содержащим отображаемые в таблице данные (все данные, не только 15 выведенных в данный момент)&lt;br /&gt;&lt;br /&gt;Во-первых, мы добавим кнопку Print на нашу панель инструментов:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;         ,&#39;-&#39;, {&lt;br /&gt;            text: &#39;Print&#39;,&lt;br /&gt;     tooltip: &#39;Print me!&#39;,&lt;br /&gt;            handler: printListing, &lt;br /&gt;            iconCls:&#39;print&#39;        // defined in our css&lt;br /&gt;          }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Давайте теперь определим функцию printListing(). Эта функция вызовет php функцию которая создаст HTML файл таблицы:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;    function printListing(){&lt;br /&gt;      var searchquery = &quot;&quot;;&lt;br /&gt;      var searchfirstname = &quot;&quot;;&lt;br /&gt;      var searchlastname = &quot;&quot;;&lt;br /&gt;      var searchparty = &quot;&quot;;&lt;br /&gt;      var searchenteringoffice = &quot;&quot;;&lt;br /&gt;      var searchleavingoffice = &quot;&quot;;&lt;br /&gt;      var win;               // our popup window&lt;br /&gt;      // check if we do have some search data...&lt;br /&gt;      if(PresidentsDataStore.baseParams.query!==null){searchquery = PresidentsDataStore.baseParams.query;}&lt;br /&gt;      if(PresidentsDataStore.baseParams.firstname!==null){searchfirstname = PresidentsDataStore.baseParams.firstname;}&lt;br /&gt;      if(PresidentsDataStore.baseParams.lastname!==null){searchlastname = PresidentsDataStore.baseParams.lastname;}&lt;br /&gt;      if(PresidentsDataStore.baseParams.party!==null){searchparty = PresidentsDataStore.baseParams.party;}&lt;br /&gt;      if(PresidentsDataStore.baseParams.enteringoffice!==null){searchenteringoffice = PresidentsDataStore.baseParams.enteringoffice;}&lt;br /&gt;      if(PresidentsDataStore.baseParams.leavingoffice!==null){searchleavingoffice = PresidentsDataStore.baseParams.leavingoffice;}&lt;br /&gt;         &lt;br /&gt;      Ext.Ajax.request({   &lt;br /&gt;        waitMsg: &#39;Please Wait...&#39;,&lt;br /&gt;        url: &#39;database.php&#39;,&lt;br /&gt;        params: {&lt;br /&gt;          task: &quot;PRINT&quot;,&lt;br /&gt;               // we have to send all of the search&lt;br /&gt;&lt;br /&gt;          query: searchquery,                                 // if we are doing a quicksearch, use this&lt;br /&gt;          firstname&amp;nbsp;: searchfirstname,                        // if we are doing advanced search, use this&lt;br /&gt;          lastname&amp;nbsp;: searchlastname,&lt;br /&gt;          party&amp;nbsp;: searchparty,&lt;br /&gt;          enteringoffice&amp;nbsp;: searchenteringoffice,&lt;br /&gt;          leavingoffice&amp;nbsp;: searchleavingoffice,&lt;br /&gt;          currentlisting: PresidentsDataStore.baseParams.task // this tells us if we are searching or not&lt;br /&gt;        }, &lt;br /&gt;        success: function(response){              &lt;br /&gt;          var result=eval(response.responseText);&lt;br /&gt;          switch(result){&lt;br /&gt;          case 1:&lt;br /&gt;            win = window.open(&#39;./presidentslist.html&#39;,&#39;presidentslist&#39;,&#39;height=400,width=600,resizable=1,scrollbars=1, menubar=1&#39;);&lt;br /&gt;            win.print();&lt;br /&gt;            break;&lt;br /&gt;          default:&lt;br /&gt;            Ext.MessageBox.alert(&#39;Uh hu...&#39;,&#39;Unable to print the grid!&#39;);&lt;br /&gt;            break;&lt;br /&gt;          }  &lt;br /&gt;        },&lt;br /&gt;        failure: function(response){&lt;br /&gt;          var result=response.responseText;&lt;br /&gt;          Ext.MessageBox.alert(&#39;error&#39;,&#39;could not connect to the database. retry later&#39;);      &lt;br /&gt;        }                      &lt;br /&gt;      });&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ок, вы можете удивится почему мы должны передавать так много параметров... Дело в том что... мы хотим распечатать всю нашу таблицу а наш DataStore содержит лишь 15 записей. Поэтому наш PHP файл собирается сделать запросы заново еще раз. не ограничивая поиск частичными запросами. Затем наш database.php сложит все это в файл listpresidents.html.&lt;br /&gt;&lt;br /&gt;Вот наш database.php файл (сначала выбор) &lt;br /&gt;&lt;pre&gt;    case &quot;PRINT&quot;:&lt;br /&gt;        printPresidents();&lt;br /&gt;        break;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;А затем функция печати:&lt;br /&gt;&lt;pre&gt;function printPresidents()&lt;br /&gt;{&lt;br /&gt;   // Ok since we limited our queries to 15 entries, we need to do a query again and get everything.&lt;br /&gt;   if($_POST[&#39;currentlisting&#39;]==&#39;LISTING&#39;){  // we are doing a basic listing or using the quicksearch&lt;br /&gt;        $query = &quot;SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty&quot;;&lt;br /&gt;        // Here we check if we have a query parameter&amp;nbsp;:&lt;br /&gt;        if (isset($_POST[&#39;query&#39;]) &amp;amp;&amp;amp; ($_POST[&#39;query&#39;]&amp;nbsp;!= &quot;&quot;)){&lt;br /&gt;          $query .= &quot; AND (pr.firstname LIKE &#39;%&quot;.$_POST[&#39;query&#39;].&quot;%&#39; OR pr.lastname LIKE &#39;%&quot;.$_POST[&#39;query&#39;].&quot;%&#39;)&quot;;&lt;br /&gt;        }&lt;br /&gt;        $query .= &quot; ORDER BY tookoffice&quot;;&lt;br /&gt;        $result = mysql_query($query);&lt;br /&gt;        $nbrows = mysql_num_rows($result);&lt;br /&gt;   } else if($_POST[&#39;currentlisting&#39;]==&#39;SEARCH&#39;){&lt;br /&gt;         $query = &quot;SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty&quot;;&lt;br /&gt;         $firstname = $_POST[&#39;firstname&#39;];&lt;br /&gt;         $lastname = $_POST[&#39;lastname&#39;];&lt;br /&gt;         $enteringoffice = $_POST[&#39;enteringoffice&#39;];&lt;br /&gt;         $leavingoffice = $_POST[&#39;leavingoffice&#39;];&lt;br /&gt;         $party  = $_POST[&#39;party&#39;];&lt;br /&gt;&lt;br /&gt;         if($firstname&amp;nbsp;!= &#39;&#39;){&lt;br /&gt;            $query .= &quot; AND firstname LIKE &#39;%&quot;.$firstname.&quot;%&#39;&quot;;&lt;br /&gt;         };&lt;br /&gt;         if($lastname&amp;nbsp;!= &#39;&#39;){&lt;br /&gt;            $query .= &quot; AND lastname LIKE &#39;%&quot;.$lastname.&quot;%&#39;&quot;;&lt;br /&gt;         };&lt;br /&gt;         if($party&amp;nbsp;!= &#39;&#39;){&lt;br /&gt;            $query .= &quot; AND pr.IDparty = &#39;&quot;.$party.&quot;&#39;&quot;;&lt;br /&gt;         };&lt;br /&gt;         if ($enteringoffice) {&lt;br /&gt;            $query .= &quot; AND tookoffice &amp;gt;= &#39;&quot;.$enteringoffice.&quot;&#39;&quot;;&lt;br /&gt;         };&lt;br /&gt;         if ($leavingoffice) {&lt;br /&gt;            $query .= &quot; AND leftoffice &amp;lt;= &#39;&quot;.$leavingoffice.&quot;&#39;&quot;;&lt;br /&gt;         };&lt;br /&gt;         $result = mysql_query($query);&lt;br /&gt;         $nbrows = mysql_num_rows($result);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // We now have our array, let&#39;s build our HTML file&amp;nbsp;:&lt;br /&gt;   $file = fopen(&quot;presidentslist.html&quot;,&#39;w&#39;);&lt;br /&gt;   fwrite($file, &quot;&amp;lt;!DOCTYPE html PUBLIC &#39;-//W3C//DTD XHTML 1.0 Transitional//EN&#39; &#39;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&#39;&amp;gt;&amp;lt;html xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&amp;gt;&amp;lt;head&amp;gt;&amp;lt;meta http-equiv=&#39;Content-Type&#39; content=&#39;text/html; charset=iso-8859-1&#39; /&amp;gt;&amp;lt;title&amp;gt;Printing the Grid&amp;lt;/title&amp;gt;&amp;lt;link rel=&#39;stylesheet&#39; type=&#39;text/css&#39; href=&#39;printstyle.css&#39;/&amp;gt;&amp;lt;/head&amp;gt;&quot;);&lt;br /&gt;   fwrite($file, &quot;&amp;lt;body&amp;gt;&amp;lt;table summary=&#39;Presidents List&#39;&amp;gt;&amp;lt;caption&amp;gt;The Presidents of the United States&amp;lt;/caption&amp;gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th scope=&#39;col&#39;&amp;gt;First Name&amp;lt;/th&amp;gt;&amp;lt;th scope=&#39;col&#39;&amp;gt;Last Name&amp;lt;/th&amp;gt;&amp;lt;th scope=&#39;col&#39;&amp;gt;Party&amp;lt;/th&amp;gt;&amp;lt;th scope=&#39;col&#39;&amp;gt;Entering Office&amp;lt;/th&amp;gt;&amp;lt;th scope=&#39;col&#39;&amp;gt;Leaving Office&amp;lt;/th&amp;gt;&amp;lt;th scope=&#39;col&#39;&amp;gt;Income&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tfoot&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th scope=&#39;row&#39;&amp;gt;Total&amp;lt;/th&amp;gt;&amp;lt;td colspan=&#39;4&#39;&amp;gt;&quot;);&lt;br /&gt;   fwrite($file, $nbrows);&lt;br /&gt;   fwrite($file, &quot; presidents&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/tfoot&amp;gt;&amp;lt;tbody&amp;gt;&quot;);&lt;br /&gt;   for($i = 0; $i&amp;lt; $nbrows; $i++){&lt;br /&gt;    $data = mysql_fetch_array($result);&lt;br /&gt;    fwrite($file,&#39;&amp;lt;tr&#39;);&lt;br /&gt;    if($i%1==0){&lt;br /&gt;      fwrite($file,&quot; class=&#39;odd&#39;&quot;);&lt;br /&gt;    }&lt;br /&gt;    fwrite($file, &quot;&amp;gt;&amp;lt;th scope=&#39;row&#39; id=&#39;r97&#39;&amp;gt;&quot;);&lt;br /&gt;    fwrite($file, $data[&#39;firstname&#39;]);&lt;br /&gt;    fwrite($file,&quot;&amp;lt;/th&amp;gt;&amp;lt;td&amp;gt;&quot;);&lt;br /&gt;    fwrite($file, $data[&#39;lastname&#39;]);&lt;br /&gt;    fwrite($file, &quot;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&quot;);&lt;br /&gt;    fwrite($file, $data[&#39;name&#39;]);&lt;br /&gt;    fwrite($file, &quot;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&quot;);&lt;br /&gt;    fwrite($file, codeDate($data[&#39;tookoffice&#39;]));&lt;br /&gt;    fwrite($file, &quot;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&quot;);&lt;br /&gt;    fwrite($file, codeDate($data[&#39;leftoffice&#39;]));&lt;br /&gt;    fwrite($file, &quot;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt; $&quot;);&lt;br /&gt;    fwrite($file, $data[&#39;income&#39;]);&lt;br /&gt;    fwrite($file, &quot;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&quot;);&lt;br /&gt;  }&lt;br /&gt;  fwrite($file, &quot;&amp;lt;/tbody&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot;);  &lt;br /&gt;  fclose($file);&lt;br /&gt;  echo &#39;1&#39;;        // we are done. &lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;На самом деле это очень просто. Мы просто вставляем запросы без ограничения количества записей и сохраняет полученный массив в HTML файл. Затем мы возвращаем 1.&lt;br /&gt;Как будут выглядеть результаты на самом деле зависит от вас!&lt;br /&gt;Некоторые предпочитают решения на основе экспорта в PDF формат. Вы можете найти эту информацию в топиках форумов.&lt;br /&gt;&lt;br /&gt;Что запомнить:&lt;br /&gt;Этот способ нельзя применить везде&lt;br /&gt;Он не показывает колонки в нужном выбранном порядке и видимости&lt;br /&gt;Это не самое лучшее решение.&lt;br /&gt;&lt;br /&gt;Файлы этой части можно скачать здесь http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%2011.zip</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/2012358788417021807/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-11.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/2012358788417021807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/2012358788417021807'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-11.html' title='Учебник: Grid PHP SQL Часть 11'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-2325082134775546918</id><published>2008-12-08T11:08:00.000+02:00</published><updated>2008-12-09T10:30:07.213+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Таблицы PHP SQL"/><title type='text'>Учебник: Grid PHP SQL Часть 10</title><content type='html'>Компонент быстрого поиска.&lt;br /&gt;&lt;br /&gt;Отлично... Мы почти прошли этот учебник!!! Скоро вы сможете создавать свои собственные впечатляющие таблицы. Давайте изучим компонет QuickSearch.&lt;br /&gt;Мы уже прошли тему как осуществлять обычный поиск по таблице. Для этого нужно чтобы пользователь нажал кнопку Search и ввел поля поиска... Ок, чтож, вы поймете что это может оказаться очень сложной задачей для большинства пользователей. И тут появляется мистер быстрый поиск QuickSearch. Компонент QuickSearch это просто текстовое поле в котором пользователь вводит текст для поиска, нажимает Ввод и тогда... А дальнейшее зависит от того как мы это сделаем..&lt;br /&gt;&lt;br /&gt;Давайте продолжим и сделаем так ,чтобы текст искался всей таблице.&lt;br /&gt;Отлично, до того как мы начнем нам нужно добавить еще один .js файл в заголовок HTML файла:&lt;br /&gt;&lt;pre&gt;&amp;lt;script type=&quot;text/javascript&quot; src=&quot;searchfield.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Вы можете найти файл в папке examples/form архива extjs или скачайте его по ссылке http://extjs.com/deploy/dev/examples/form/SearchField.js&lt;br /&gt;Во-первых мы просто добавим его на нашу панель инструментов. Нам просто надо установить некоторые основные параметры, которые передаем в datastore.&lt;br /&gt;&lt;pre&gt;, &#39;-&#39;, new Ext.app.SearchField({&lt;br /&gt;  store: PresidentsDataStore,&lt;br /&gt;  params: {start: 0, limit: 15},&lt;br /&gt;  width: 120&lt;br /&gt;})&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ок, если вы достаточно опытны, мы можем просто открыть файл searchfield.js в любимом Блокноте и посмотреть что там внутри... И там вы увидите параметр называемый query который посылается при перезагрузке datastore. Да... Мы знаем что есть что! Теперь.. DataStore президентов может быть как в LISTING режиме так и в режиме SEARCHING (зависит от параметров). Итак, кнопка QuickSearch будет просто добавлять строку введенную в текстовое поле как дополнительный параметр.&lt;br /&gt;Я просто собираюсь реализовать это при простом получении списка президентов. Я вам покажу как это сделать при поиске (быстрый поиск на существующем поиске)&lt;br /&gt;Давайте откроем наш файл database.php.Теперь, когда мы обращаемся к функции getList()  мы должны проверить нет ли у нас параметра query. И если есть мы должны найти похожие данные в нашей таблице. Теперь наша новая функци getList выглядит так:&lt;br /&gt;&lt;pre&gt;  $query = &quot;SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty&quot;;&lt;br /&gt;  // Here we check if we have a query parameter&amp;nbsp;:&lt;br /&gt;  if (isset($_POST[&#39;query&#39;])){&lt;br /&gt;    $query .= &quot; AND (pr.firstname LIKE &#39;%&quot;.addslashes($_POST[&#39;query&#39;]).&quot;%&#39; OR pr.lastname LIKE &#39;%&quot;.addslashes($_POST[&#39;query&#39;]).&quot;%&#39;)&quot;;&lt;br /&gt;  }&lt;br /&gt;  $result = mysql_query($query);&lt;br /&gt;  $nbrows = mysql_num_rows($result);&lt;br /&gt;  $start = (integer) (isset($_POST[&#39;start&#39;])&amp;nbsp;? $_POST[&#39;start&#39;]&amp;nbsp;: $_GET[&#39;start&#39;]);&lt;br /&gt;  $end = (integer) (isset($_POST[&#39;limit&#39;])&amp;nbsp;? $_POST[&#39;limit&#39;]&amp;nbsp;: $_GET[&#39;limit&#39;]);&lt;br /&gt;  $limit = $query.&quot; LIMIT &quot;.$start.&quot;,&quot;.$end;  &lt;br /&gt;  $result = mysql_query($limit);  &lt;br /&gt;  [...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Это так просто! :) Ну теперь вы можете брать параметр query, убрать все пробелы, разбить по словам для лучшего поиска. Вы даже можете делать поиск по годам и так далее... Реализация поиска, который мыуже сделали достаточно проста. Просто проверяйте переменную query до того, как сделаете запрос. Вот и все!&lt;br /&gt;&lt;br /&gt;Скачать файлы проекта можно по ссылке http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%2010.zip</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/2325082134775546918/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-10.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/2325082134775546918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/2325082134775546918'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-10.html' title='Учебник: Grid PHP SQL Часть 10'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-6789148989234129970</id><published>2008-12-08T11:07:00.001+02:00</published><updated>2008-12-09T10:30:07.213+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Таблицы PHP SQL"/><title type='text'>Учебник: Grid PHP SQL Часть 9</title><content type='html'>Панель страниц&lt;br /&gt;&lt;br /&gt;Ну что, это снова вы... Да... Ок, давайте поговорим о панели страниц, которую вы можете увидеть внизу таблицы. Она мне всегда очень нравилась. Самое хорошее, что реализовать ее очень просто. Так давайте быстро сделаем ее!&lt;br /&gt;&lt;br /&gt;Элемент PagingToolbar должен знать в основном две вещи: как много записей вы хотите отображать на странице и куда отсылать информацию о текущей странице.(мы будем посылать эту информацию в DataStore)&lt;br /&gt;Итак... Сразу после панели инструментов в EditorGrid, давайте добавим нижнюю панель:&lt;br /&gt;&lt;pre&gt;      bbar: new Ext.PagingToolbar({&lt;br /&gt;                pageSize: 15,&lt;br /&gt;                store: PresidentsDataStore,&lt;br /&gt;                displayInfo: true&lt;br /&gt;            })&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Мы будем показывать по 15 президентов на странице. Мы уже почти все сделали! Единственная вещь теперь - как сообщить нашему PHP скрипту как мы будем делать наш постраничный просмотр. Элемент PagingToolbar использует два параметра - start (стартовая запись) и limit (количество записей). Они будут доступны в серверном скрипте и мы должны лишь только учесть их в нашем SQL запросе.&lt;br /&gt;Давайте убедимся что посылаем эти параметры каждый раз, когда нам нужен список президентов: Каждую PresidentsDataStore.reload()  или PresidentsDataStore.load() мы трансформируем в:&lt;br /&gt;&lt;pre&gt;  PresidentsDataStore.reload({params: {start: 0, limit: 15}});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Сделайте изменения сами (они встречаются в mainscript.js) только в 3 местах)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Серверная часть &lt;br /&gt;Это очень просто. Теперь, когда мы имеем переменные start и limit, нам нужно получить их значения и изменить конец нашего SQL запроса.&lt;br /&gt;Вот изменения в фукции getList():&lt;br /&gt;&lt;pre&gt;  $query = &quot;SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty&quot;;&lt;br /&gt;  $result = mysql_query($query);&lt;br /&gt;  $nbrows = mysql_num_rows($result);&lt;br /&gt;  // Add this for the paging bar:&lt;br /&gt;  $start = (integer) (isset($_POST[&#39;start&#39;])&amp;nbsp;? $_POST[&#39;start&#39;]&amp;nbsp;: $_GET[&#39;start&#39;]);&lt;br /&gt;  $end = (integer) (isset($_POST[&#39;limit&#39;])&amp;nbsp;? $_POST[&#39;limit&#39;]&amp;nbsp;: $_GET[&#39;limit&#39;]);&lt;br /&gt;  $limit = $query.&quot; LIMIT &quot;.$start.&quot;,&quot;.$end;  &lt;br /&gt;  $result = mysql_query($limit); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Мы все еще хотим делать первый запрос так, чтбы получить общее количество записей (nbrows), но обратно в Ext будем отсылать массим содержащий 15 или менее записей, которые были запрошены.&lt;br /&gt;Давайте не забудем сделать эти же изменения в функции поиска searchPresidents().&lt;br /&gt;&lt;br /&gt;Файл с материалами этой части учебника здесь http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%209.zip</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/6789148989234129970/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-9.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6789148989234129970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/6789148989234129970'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-9.html' title='Учебник: Grid PHP SQL Часть 9'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-5224648142039255871</id><published>2008-12-05T13:14:00.007+02:00</published><updated>2008-12-09T10:30:07.213+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Таблицы PHP SQL"/><title type='text'>Учебник: Grid PHP SQL Часть 8</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Поиск по таблице&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Отлично.. Как вы можете видеть мы может форматировать нашу таблицу так как захотим. Сегодня мы собираемся научиться как что-нибудь искать в таблице. Легко найти Джона Кеннеди, не потому конечно, что знаешь дату его избрания, но так же потому, что в нашей таблице всего 40 записей. Другое дело, если мы включили всех политиков США... Следовательно мы должны дать пользователю возможность сужать поиск.&lt;br /&gt;&lt;br /&gt;Создание формы поиска&lt;br /&gt;&lt;br /&gt;Когда мы создали форму мы объявили некоторые поля как глобальные переменные и работали с ними через методы name.setValue() или getValue(). Помните, что из-за этого мы можем иметь только одну форму для добавления записей. В нашем случае это не ограничивает ничего, а целью было сосредоточиться на табличной системе ext. Однако, чтобы показать как подобные вещи следует делать мы создадим следующую форму без глобальных переменных. Следовательно мы сможем открывать несколько форм поиска одновременно. Это очень полезно в наши дни.&lt;br /&gt;Вот как мы сделаем. Когда мы наживаем на кнопку Advanced Search (Расширенный поиск) мы хотим, чтобы открылось новое окно для поиска с пустыми полями и готовое для поиска. Мы бы хотели сделать окно с расширенным поиском по нескольким полям.&lt;br /&gt; &lt;br /&gt;Сначала, довайте добавим кнопку поиска Search в панель инструментов (в PresidentListingEditorGrid):&lt;br /&gt;&lt;pre&gt;          }, &#39;-&#39;, {&lt;br /&gt;            text: &#39;Search&#39;,&lt;br /&gt;            tooltip: &#39;Advanced Search&#39;,&lt;br /&gt;            handler: startAdvancedSearch,  // search function&lt;br /&gt;            iconCls:&#39;search&#39;               // we&#39;ll need to add this to our css&lt;br /&gt;          }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Давайте определим нашу функцию startAdvancedSearch. Вот немного для начала:&lt;br /&gt;&lt;pre&gt;  function startAdvancedSearch(){&lt;br /&gt;      // local vars&lt;br /&gt;      var PresidentSearchForm;&lt;br /&gt;      var PresidentSearchWindow;&lt;br /&gt;      var SearchFirstNameItem;&lt;br /&gt;      var SearchLastNameItem;&lt;br /&gt;      var SearchPartyItem;&lt;br /&gt;      var SearchEnteringItem;&lt;br /&gt;      var SearchLeavingItem;&lt;br /&gt;      &lt;br /&gt;      SearchFirstNameItem = new Ext.form.TextField({&lt;br /&gt;          fieldLabel: &#39;First Name&#39;,&lt;br /&gt;          maxLength: 20,&lt;br /&gt;          anchor&amp;nbsp;: &#39;95%&#39;,&lt;br /&gt;          maskRe: /([a-zA-Z0-9\s]+)$/&lt;br /&gt;            });&lt;br /&gt;&lt;br /&gt;      SearchLastNameItem = new Ext.form.TextField({&lt;br /&gt;          fieldLabel: &#39;Last Name&#39;,&lt;br /&gt;          maxLength: 20,&lt;br /&gt;          anchor&amp;nbsp;: &#39;95%&#39;,    &lt;br /&gt;          maskRe: /([a-zA-Z0-9\s]+)$/  &lt;br /&gt;            });&lt;br /&gt;      &lt;br /&gt;      SearchPartyItem = new Ext.form.ComboBox({&lt;br /&gt;         fieldLabel: &#39;Party&#39;,&lt;br /&gt;         store:new Ext.data.SimpleStore({&lt;br /&gt;          fields:[&#39;partyValue&#39;, &#39;partyName&#39;],&lt;br /&gt;          data: [[&#39;1&#39;,&#39;No Party&#39;],[&#39;2&#39;,&#39;Federalist&#39;],[&#39;3&#39;,&#39;Democratic-Republican&#39;],[&#39;4&#39;,&#39;Democratic&#39;],[&#39;5&#39;,&#39;Whig&#39;],[&#39;6&#39;,&#39;Republican&#39;]]&lt;br /&gt;          }),&lt;br /&gt;         mode: &#39;local&#39;,&lt;br /&gt;         displayField: &#39;partyName&#39;,&lt;br /&gt;         valueField: &#39;partyValue&#39;,&lt;br /&gt;         anchor:&#39;95%&#39;,&lt;br /&gt;         triggerAction: &#39;all&#39;&lt;br /&gt;            });&lt;br /&gt;            &lt;br /&gt;      SearchEnteringItem = new Ext.form.DateField({&lt;br /&gt;          fieldLabel: &#39;Entered Office after&#39;,&lt;br /&gt;          format&amp;nbsp;: &#39;m/d/Y&#39;,&lt;br /&gt;          anchor:&#39;95%&#39;&lt;br /&gt;          });&lt;br /&gt;          &lt;br /&gt;      SearchLeavingItem = new Ext.form.DateField({&lt;br /&gt;          fieldLabel: &#39;Left Office before&#39;,&lt;br /&gt;          format&amp;nbsp;: &#39;m/d/Y&#39;,&lt;br /&gt;          anchor:&#39;95%&#39;&lt;br /&gt;          });&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Знакомо выглядит? Так и должно быть!!! Это почти тоже самое что  мы делали при создании формы.. За исключеним того, что мы не указываем никакие идентификаторы (запомните, что они должны быть уникальны, мы не можем иметь несколько элементов с одинаковыми id) Другое огромное отличие в том, что каждое поле, форма или окно определено прямо в функции. Нам не нужно беспокоится о скрытии окна, мы просто можем открыть другое окно как только это закроется.&lt;br /&gt;Продолжим:&lt;br /&gt;&lt;pre&gt;     PresidentSearchForm = new Ext.FormPanel({&lt;br /&gt;       labelAlign: &#39;top&#39;,&lt;br /&gt;       bodyStyle: &#39;padding: 5px&#39;,&lt;br /&gt;       width: 300,&lt;br /&gt;       items: [{&lt;br /&gt;         layout: &#39;form&#39;,&lt;br /&gt;         border: false,&lt;br /&gt;         items: [ SearchFirstNameItem,SearchLastNameItem,SearchPartyItem,SearchEnteringItem, SearchLeavingItem ],&lt;br /&gt;         buttons: [{&lt;br /&gt;               text: &#39;Search&#39;,&lt;br /&gt;               handler: listSearch&lt;br /&gt;             },{&lt;br /&gt;               text: &#39;Close&#39;,&lt;br /&gt;               handler: resetSearch&lt;br /&gt;             }]&lt;br /&gt;         }]&lt;br /&gt;     });&lt;br /&gt;      &lt;br /&gt;     PresidentSearchWindow = new Ext.Window({&lt;br /&gt;         title: &#39;President Search&#39;,&lt;br /&gt;         closable:true,&lt;br /&gt;         width: 200,&lt;br /&gt;         height: 400,&lt;br /&gt;         plain:true,&lt;br /&gt;         layout: &#39;fit&#39;,&lt;br /&gt;         items: PresidentSearchForm&lt;br /&gt;     });&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Важный момент в этом коде - просто вызовы двух функций, listSearch и resetSearch, которые должны быть определены здесь же локально (смотри следующий параграф) чтобы позволить им получить доступ к локальным значениям полей. У нас есть кнопки Search (искать) и Close (закрыть). Кнопка Search будет запускать поиск а кнопка Close, то очень интересно, также будет выполнять поиск. Вот почему...&lt;br /&gt;&lt;pre&gt;    function listSearch(){&lt;br /&gt;         // render according to a SQL date format.&lt;br /&gt;         var startDate = &quot;&quot;;&lt;br /&gt;         var endDate = &quot;&quot;;&lt;br /&gt;         if(SearchEnteringItem.getValue()&amp;nbsp;!= &quot;&quot;) {&lt;br /&gt;            startDate = SearchEnteringItem.getValue().format(&#39;Y-m-d&#39;);&lt;br /&gt;         }&lt;br /&gt;         if(SearchLeavingItem.getValue()&amp;nbsp;!= &quot;&quot;) {&lt;br /&gt;            endDate = SearchLeavingItem.getValue().format(&#39;Y-m-d&#39;);&lt;br /&gt;         }&lt;br /&gt;         &lt;br /&gt;         // change the store parameters&lt;br /&gt;         PresidentsDataStore.baseParams = {&lt;br /&gt;      task: &#39;SEARCH&#39;,&lt;br /&gt;      firstname: SearchFirstNameItem.getValue(),&lt;br /&gt;            lastname&amp;nbsp;: SearchLastNameItem.getValue(),&lt;br /&gt;            party&amp;nbsp;: SearchPartyItem.getValue(),&lt;br /&gt;            enteringoffice&amp;nbsp;: startDate,&lt;br /&gt;            leavingoffice&amp;nbsp;: endDate&lt;br /&gt;     };&lt;br /&gt;         // Cause the datastore to do another query&amp;nbsp;: &lt;br /&gt;     PresidentsDataStore.reload();&lt;br /&gt;     }&lt;br /&gt;     &lt;br /&gt;     function resetSearch(){&lt;br /&gt;         // reset the store parameters&lt;br /&gt;      PresidentsDataStore.baseParams = {&lt;br /&gt;      task: &#39;LISTING&#39;&lt;br /&gt;     };&lt;br /&gt;         // Cause the datastore to do another query&amp;nbsp;: &lt;br /&gt;     PresidentsDataStore.reload();&lt;br /&gt;         PresidentSearchWindow.close();&lt;br /&gt;     }&lt;br /&gt;     &lt;br /&gt;     // once all is done, show the search window&lt;br /&gt;     PresidentSearchWindow.show();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Видите почему? Все что мы делаем это берем оригинальный datastore и изменяем его параметры. Мы затем просим его перезагрузится. А это выполняет новый запрос. Результаты затем отображаются так же как и в начале учебника.&lt;br /&gt;Это объясняет функцию resetSearch. Чтобы сбросить поиск, мы должны установить оригинальные параметры DataStore (а это просто задача listing). Затем мы перезагружаем наш DataStore.&lt;br /&gt;&lt;br /&gt;Маленькое упражнение с запросами&lt;br /&gt;Вы уже использовали эти Ajax запросы? Серверный скрипт просто обрабатывает это вызов как любой другой... Давайте запишем ( в database.php)&lt;br /&gt;&lt;br /&gt;Сначала в выборе : &lt;br /&gt;&lt;pre&gt;    case &quot;SEARCH&quot;:&lt;br /&gt;        searchPresidents();&lt;br /&gt;        break;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;а затем идет наша функция searchPresidents() &lt;br /&gt;&lt;pre&gt;function searchPresidents()&lt;br /&gt;{&lt;br /&gt;   $query = &quot;SELECT * FROM presidents pr, parties pa WHERE pr.IDparty = pa.IDparty&quot;;&lt;br /&gt;&lt;br /&gt;   $firstname = $_POST[&#39;firstname&#39;];&lt;br /&gt;   $lastname = $_POST[&#39;lastname&#39;];&lt;br /&gt;   $enteringoffice = $_POST[&#39;enteringoffice&#39;];&lt;br /&gt;   $leavingoffice = $_POST[&#39;leavingoffice&#39;];&lt;br /&gt;   $party  = $_POST[&#39;party&#39;];&lt;br /&gt;  &lt;br /&gt;   if($firstname&amp;nbsp;!= &#39;&#39;){&lt;br /&gt;      $query .= &quot; AND firstname LIKE &#39;%&quot;.$firstname.&quot;%&#39;&quot;;&lt;br /&gt;   };&lt;br /&gt;   if($lastname&amp;nbsp;!= &#39;&#39;){&lt;br /&gt;      $query .= &quot; AND lastname LIKE &#39;%&quot;.$lastname.&quot;%&#39;&quot;;&lt;br /&gt;   };&lt;br /&gt;   if($party&amp;nbsp;!= &#39;&#39;){&lt;br /&gt;      $query .= &quot; AND pr.IDparty = &#39;&quot;.$party.&quot;&#39;&quot;;&lt;br /&gt;   };&lt;br /&gt;   if ($enteringoffice) {&lt;br /&gt;        $query .= &quot; AND tookoffice &amp;gt;= &#39;&quot;.$enteringoffice.&quot;&#39;&quot;;&lt;br /&gt;     };&lt;br /&gt;   if ($leavingoffice) {&lt;br /&gt;        $query .= &quot; AND leftoffice &amp;lt;= &#39;&quot;.$leavingoffice.&quot;&#39;&quot;;&lt;br /&gt;     };&lt;br /&gt;    &lt;br /&gt;   $result = mysql_query($query);&lt;br /&gt;   $nbrows = mysql_num_rows($result);  &lt;br /&gt;   if($nbrows&amp;gt;0){&lt;br /&gt;    while($rec = mysql_fetch_array($result)){&lt;br /&gt;            // render the right date format&lt;br /&gt;      $rec[&#39;tookoffice&#39;]=codeDate($rec[&#39;tookoffice&#39;]);&lt;br /&gt;      $rec[&#39;leftoffice&#39;]=codeDate($rec[&#39;leftoffice&#39;]);      &lt;br /&gt;      $arr[] = $rec;&lt;br /&gt;    }&lt;br /&gt;    $jsonresult = JEncode($arr);&lt;br /&gt;    echo &#39;({&quot;total&quot;:&quot;&#39;.$nbrows.&#39;&quot;,&quot;results&quot;:&#39;.$jsonresult.&#39;})&#39;;&lt;br /&gt;   } else {&lt;br /&gt;    echo &#39;({&quot;total&quot;:&quot;0&quot;, &quot;results&quot;:&quot;&quot;})&#39;;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Итак мы рассмотрели простой поиск. И он работает достаточно хорошо. Теперь у вас может быть сотни записей а найти любую из них вы сможете очень быстро.&lt;br /&gt;&lt;br /&gt;Что запомнить из этой части:&lt;br /&gt;id обьектов должны быть уникальны&lt;br /&gt;Работа с параметрами DataStore&lt;br /&gt;&lt;br /&gt;Файлы этой части можно &lt;a href=&quot;http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%208.zip&quot;&gt;скачать здесь&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Источник: &lt;a href=&quot;http://extjs.com/learn/w/index.php?title=Tutorial:Grid_PHP_SQL_Part8&quot;&gt;http://extjs.com/learn/w/index.php?title=Tutorial:Grid_PHP_SQL_Part8&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/5224648142039255871/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-8.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/5224648142039255871'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/5224648142039255871'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-8.html' title='Учебник: Grid PHP SQL Часть 8'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-3155898268979600836</id><published>2008-12-05T12:44:00.006+02:00</published><updated>2008-12-09T10:30:07.214+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Таблицы PHP SQL"/><title type='text'>Учебник: Grid PHP SQL Часть 7</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Настраиваемые CSS стили&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Отлично, рад видеть, что вы все еще со мной! Если вы зашли так далеко, то вы уже наверное обладаете знаниями о редактировании, добавлении и удалении записей в таблице. Вы наверное провели часы, играясь с таблицей и потратили много времени, показывая свои достижения детям, супруге, родителям а может даже своей собаке. Наиболее вероятно, они ответили: &quot;Отлично! Но есть ли вариант изменить css стиль вот тех ячеек??&quot; Чтож, звучит загадочно.. ЭТО ВОЗМОЖНО! И... это на самом деле не очень сложно...&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;br /&gt;Давайте начнем сначала&lt;/span&gt;&lt;br /&gt;В каждую колонку, добавленную в ColumnModel, мы можем добавить параметр, называемый renderer (построитель). Этот параметр просто функция, которая позволяет нам сказать Ext как отображать ячейки в этой колонке.&lt;br /&gt;Функция постройки имеет 6 параметров: (data (данные), cell (ячейка), rowIndex (индекс ряда), columnIndex (индекс колонки), store). Играя с этими значениями мы можем установить любой стиль в нужном месте. На самом деле, это почти то же самое, что мы уже сделали в нашем NumberField... (мы написали &#39;$&#39; прямо за значением)&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Играем с цветами&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Мы найдем президентов, которые имели больше всего голосов. Для этого мы изменим цвет ячейки голосов в соответствии с её значением. Нам надо изменить функцию постройки колонки Income:&lt;br /&gt;&lt;pre&gt;        renderer: function(value, cell){ &lt;br /&gt;         var str = &#39;&#39;;&lt;br /&gt;         if(value &amp;gt; 1000000){&lt;br /&gt;            str = &quot;&amp;lt;span style=&#39;color:#336600;&#39;&amp;gt;$ &quot; + value + &quot;&amp;lt;/span&amp;gt;&quot;;&lt;br /&gt;         } else if (value &amp;gt; 100000 &amp;amp;&amp;amp; value &amp;lt; 1000000){&lt;br /&gt;            str = &quot;&amp;lt;span style=&#39;color:#FF9900;&#39;&amp;gt;$ &quot; + value + &quot;&amp;lt;/span&amp;gt;&quot;;&lt;br /&gt;         } else {&lt;br /&gt;            str = &quot;&amp;lt;span style=&#39;color:#CC0000;&#39;&amp;gt;$ &quot; + value + &quot;&amp;lt;/span&amp;gt;&quot;;&lt;br /&gt;         }&lt;br /&gt;         return str; &lt;br /&gt;        },&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Играем с css стилями&lt;br /&gt;&lt;br /&gt;Вы наверное показывали вашу таблицу друзьям а те очень сердились, что не могут изменить идентификаторы ID президентов (эта колонка доступна для редактирования) и должно быть убили вашу мышку так, как будто играли в Diablo очень много времени. Давайте убережемся от таких друзей и изменим css стили ячеек. Это просто делается через cell.css поле.&lt;br /&gt;Давайте добавим следующий код в style.css : &lt;br /&gt;&lt;pre&gt;.readonlycell { &lt;br /&gt;  background-color:#CCCCCC&amp;nbsp;!important;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Теперь для IDPresident и IDParty давайте добавить построитель, который установит css стили для ячеек:&lt;br /&gt;&lt;pre&gt;        renderer: function(value, cell){ &lt;br /&gt;         cell.css = &quot;readonlycell&quot;;&lt;br /&gt;         return value;&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Запомните, функция построителя должна возвращать какие-то данные. Иначе вы не увидите ничего...&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Любой стиль для любой ячейки&lt;/span&gt;&lt;br /&gt;Как вы можете видеть, вы можете изменять ячейки так как захотите. В данном примере, мы изменили фоновое изображение для имени и фамилии президента. Просто так, без причины.. Я бы не советовар перегружать вашу таблицу большим количеством css стилей, так как иначе ваши глаза просто заболят, когда таблица появится на экране.&lt;br /&gt;&lt;br /&gt;Что запомнить из этой части:&lt;br /&gt;Используйте css стили лишь для того, чтобы было понятно и удобно работать с таблицой.&lt;br /&gt;&lt;br /&gt;Файлы этой части можно &lt;a href=&quot;http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%207.zip&quot;&gt;скачать здесь&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Источник: &lt;a href=&quot;http://extjs.com/learn/w/index.php?title=Tutorial:Grid_PHP_SQL_Part7&quot;&gt;http://extjs.com/learn/w/index.php?title=Tutorial:Grid_PHP_SQL_Part7&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/3155898268979600836/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-7.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/3155898268979600836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/3155898268979600836'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-7.html' title='Учебник: Grid PHP SQL Часть 7'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-5976388561252006839</id><published>2008-12-05T11:36:00.006+02:00</published><updated>2008-12-09T10:30:07.214+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Таблицы PHP SQL"/><title type='text'>Учебник: Grid PHP SQL Часть 6</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Удаление записи&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;В предыдущих частях мы создали редактируемую таблицу с функцией добавления записей в нее. Давайте подумаем. Мы еще многое не реализовали, но уже написали пару сотен строк кода...&lt;br /&gt;Это показывает насколько важно структурировать код. Есть множество топиков на форумах и учебников как правильно писать Ext код. Убедитесь, что используете Firefox и отладчик (Firebug) и проверяйте результаты в IE. Вы можете проверять ваши .js файлы с помощью &lt;a href=&quot;http://www.jslint.com/&quot;&gt;JSLint&lt;/a&gt; чтобы убедится в их корректности. Очень легко потеряться в Ext коде, так как большинство структур построено в Json формате. Правильно расставляйте отступы. Если вам еще не понятно, посмотрите &lt;a href=&quot;http://extjs.com/forum/showthread.php?t=27784&amp;highlight=grid+faq&quot;&gt;ЧАВО от Mickael&#39;s&lt;/a&gt; по таблицам.&lt;br /&gt;&lt;br /&gt;Эта часть учебника научит нас удалять записи из таблицы. Это будет очень просто. Мы просто выбираем ряд таблицы и нажимаем кнопку Delete (Удалить), Ajax запрос посылается и трансформируется в SQL запрос, как мы делали в других случаях. Вы просто можете попробовать сделать это и посмотреть как это легко.&lt;br /&gt;&lt;br /&gt;А что делать если мы хотим удалить несколько рядов. Как это сделать?? Вы можете выбирать носколько рядов с помощью CTRL или SHIFT.. Видите? Чтобы удалить все эти ряды мы должны их все обработать и мы это сделаем с помощью цикла и создадим массив который будет содержать все идентификаторы IDPresidents для каждого ряда. Затем мы просто перекодируем массив и отошлем его на сервер как параметр.&lt;br /&gt;&lt;br /&gt;Давайте посмотрим, как это сделать:&lt;br /&gt;&lt;pre&gt;  var selections = PresidentListingEditorGrid.selModel.getSelections();&lt;br /&gt;  var prez = [];&lt;br /&gt;  for(i = 0; i&amp;lt; PresidentListingEditorGrid.selModel.getCount(); i++){&lt;br /&gt;    prez.push(selections[i].json.IDpresident);&lt;br /&gt;  }&lt;br /&gt;  var encoded_array = Ext.encode(prez);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Как вы можете видеть этот код достаточно прямолинейный. Давайте внедрим его в наш скрипт.&lt;br /&gt;Во-первых давайте добавим кнопку удаления на панель инструментов (мы также добавили CSS код), вот так:&lt;br /&gt;&lt;pre&gt;  tbar: [&lt;br /&gt;    {&lt;br /&gt;      text: &#39;Add a President&#39;,&lt;br /&gt;      tooltip: &#39;Great tooltips...&#39;,&lt;br /&gt;      iconCls:&#39;add&#39;,                      // reference to our css&lt;br /&gt;      handler: displayFormWindow&lt;br /&gt;    }, &#39;-&#39;, {&lt;br /&gt;      text: &#39;Delete selection&#39;,&lt;br /&gt;      tooltip: &#39;Jose, can you seeeee??&#39;,&lt;br /&gt;      handler: confirmDeletePresidents,   // Confirm before deleting&lt;br /&gt;      iconCls:&#39;remove&#39;&lt;br /&gt;  }]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Так как люди, которые будут использовать ваши приложения не всегда сообразительны (я не исключение) и могут просто нажать кнопку удаления случайно, нам нужно спросить подтверждение для удаления с помощью функции:&lt;br /&gt;&lt;pre&gt;  function confirmDeletePresidents(){&lt;br /&gt;    if(PresidentListingEditorGrid.selModel.getCount() == 1) // only one president is selected here&lt;br /&gt;    {&lt;br /&gt;      Ext.MessageBox.confirm(&#39;Confirmation&#39;,&#39;Do you not like that president at all?&#39;, deletePresidents);&lt;br /&gt;    } else if(PresidentListingEditorGrid.selModel.getCount() &amp;gt; 1){&lt;br /&gt;      Ext.MessageBox.confirm(&#39;Confirmation&#39;,&#39;Delete those presidents?&#39;, deletePresidents);&lt;br /&gt;    } else {&lt;br /&gt;      Ext.MessageBox.alert(&#39;Uh oh...&#39;,&#39;You can\&#39;t really delete something you haven\&#39;t selected huh?&#39;);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Полная функция удаления&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Итак, что мы имеем:&lt;br /&gt;&lt;pre&gt;  function deletePresidents(btn){&lt;br /&gt;    if(btn==&#39;yes&#39;){&lt;br /&gt;         var selections = PresidentListingEditorGrid.selModel.getSelections();&lt;br /&gt;         var prez = [];&lt;br /&gt;         for(i = 0; i&amp;lt; PresidentListingEditorGrid.selModel.getCount(); i++){&lt;br /&gt;          prez.push(selections[i].json.IDpresident);&lt;br /&gt;         }&lt;br /&gt;         var encoded_array = Ext.encode(prez);&lt;br /&gt;         Ext.Ajax.request({  &lt;br /&gt;            waitMsg: &#39;Please Wait&#39;,&lt;br /&gt;            url: &#39;database.php&#39;, &lt;br /&gt;            params: { &lt;br /&gt;               task: &quot;DELETEPRES&quot;, &lt;br /&gt;               ids:  encoded_array&lt;br /&gt;              }, &lt;br /&gt;            success: function(response){&lt;br /&gt;              var result=eval(response.responseText);&lt;br /&gt;              switch(result){&lt;br /&gt;              case 1:  // Success&amp;nbsp;: simply reload&lt;br /&gt;                PresidentsDataStore.reload();&lt;br /&gt;                break;&lt;br /&gt;              default:&lt;br /&gt;                Ext.MessageBox.alert(&#39;Warning&#39;,&#39;Could not delete the entire selection.&#39;);&lt;br /&gt;                break;&lt;br /&gt;              }&lt;br /&gt;            },&lt;br /&gt;            failure: function(response){&lt;br /&gt;              var result=response.responseText;&lt;br /&gt;              Ext.MessageBox.alert(&#39;error&#39;,&#39;could not connect to the database. retry later&#39;);      &lt;br /&gt;              }&lt;br /&gt;         });&lt;br /&gt;      }  &lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Теперь подкорректируем серверный скрипт database.php:&lt;br /&gt;&lt;br /&gt;Наши варианты выбора пополнятся: &lt;br /&gt;&lt;pre&gt;    case &quot;DELETEPRES&quot;:&lt;br /&gt;        deletePresidents();&lt;br /&gt;        break;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;А теперь нам нужно реализовать функцию deletePresidents(). Эта небольшая часть, которая строит запрос взависимости от выбора. На не нужно делать столько же запросов, сколько нам нужно удалить записей. Мы должны сделать все удаления в одном запросе. (Firebug очень здесь поможет) В любом случаем запрос создается следующей функцией:&lt;br /&gt;&lt;pre&gt;function deletePresidents(){&lt;br /&gt;   $ids = $_POST[&#39;ids&#39;]; // Get our array back and translate it&amp;nbsp;:&lt;br /&gt;   if (version_compare(PHP_VERSION,&quot;5.2&quot;,&quot;&amp;lt;&quot;))  {    &lt;br /&gt;     require_once(&quot;./JSON.php&quot;); &lt;br /&gt;     $json = new Services_JSON();&lt;br /&gt;     $idpres = $json-&amp;gt;decode(stripslashes($ids));&lt;br /&gt;   } else {&lt;br /&gt;     $idpres = json_decode(stripslashes($ids));&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;    // You could do some checkups here and return &#39;0&#39; or other error consts.&lt;br /&gt;    &lt;br /&gt;    // Make a single query to delete all of the presidents at the same time&amp;nbsp;:&lt;br /&gt;    if(sizeof($idpres)&amp;lt;1){&lt;br /&gt;      echo &#39;0&#39;;&lt;br /&gt;    } else if (sizeof($idpres) == 1){&lt;br /&gt;      $query = &quot;DELETE FROM presidents WHERE IDpresident = &quot;.$idpres[0];&lt;br /&gt;      mysql_query($query);&lt;br /&gt;    } else {&lt;br /&gt;      $query = &quot;DELETE FROM presidents WHERE &quot;;&lt;br /&gt;      for($i = 0; $i &amp;lt; sizeof($idpres); $i++){&lt;br /&gt;         $query = $query . &quot;IDpresident = &quot;.$idpres[$i];&lt;br /&gt;         if($i&amp;lt;sizeof($idpres)-1){&lt;br /&gt;            $query = $query . &quot; OR &quot;;&lt;br /&gt;         }     &lt;br /&gt;      }&lt;br /&gt;      mysql_query($query);&lt;br /&gt;    }&lt;br /&gt;    // echo $query;  This helps me find out what the heck is going on in Firebug...&lt;br /&gt;    echo &#39;1&#39;;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Что надо запомнить из этой части:&lt;br /&gt;SelectionModels&lt;br /&gt;Firebug сохранит много вашего времени&lt;br /&gt;&lt;br /&gt;Файлы этой части вы &lt;a href=&quot;http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%206.zip&quot;&gt;найдете здесь&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Источник: &lt;a href=&quot;http://extjs.com/learn/w/index.php?title=Tutorial:Grid_PHP_SQL_Part6&quot;&gt;http://extjs.com/learn/w/index.php?title=Tutorial:Grid_PHP_SQL_Part6&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/5976388561252006839/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-6.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/5976388561252006839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/5976388561252006839'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-6.html' title='Учебник: Grid PHP SQL Часть 6'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-992119016619597159.post-1153689412130691310</id><published>2008-12-05T10:44:00.010+02:00</published><updated>2008-12-09T10:30:07.214+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ext"/><category scheme="http://www.blogger.com/atom/ns#" term="Ext.Учебник.Таблицы PHP SQL"/><title type='text'>Учебник: Grid PHP SQL Часть 5</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;Добавление новой записи&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Отлично, мы создали нашу таблицу и теперь даже можем вносить в нее изменения. Они записываются прямо в нашу SQL таблицу. Эта часть учебника научит вас добавлять новые записи в таблицу.&lt;br /&gt;&lt;br /&gt;Есть много путей сделать это. Один из вариантов - это вставка пустой новой записи и ее редактирование. Это вариант, предпочитаемый M. LeCompte. Мы собираемся сделать это несколько другим способом. Мы создадим новое окно, которое будет содержать форму для заполнения данных президента.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Создание формы&lt;/span&gt;&lt;br /&gt;Отлично, давайте посмотрим, какие поля формы нам понадобятся:&lt;br /&gt;    * Текстовое поле имени президента&lt;br /&gt;    * Текстовое поле фамилии&lt;br /&gt;    * Два поля даты - для ввода дат президентсва.&lt;br /&gt;    * Числовое поле для ввода поступлений&lt;br /&gt;    * Выпадающий список для партии &lt;br /&gt;&lt;br /&gt;Все это надо поместить в форму и отобразить в окне. Давайте сделаем это вначале скрипта:&lt;br /&gt;&lt;pre&gt;  var PresidentCreateForm;&lt;br /&gt;  var PresidentCreateWindow;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Чтобы каджому все было ясно и понятно мы будем создавать каждое поле до того, как добавлять его в форму. Каждое поле будет глобальной переменной (это не лучший вариант, позже вы сможете создавать различные идентификаторы для каждого поля и ссылаться на них) Просто запомните, вам бы не захотелось иметь 35078 глобальных переменных в программе... Также, почему мы делаем сейчас все таким способом - это защита от запуска двух форм одновременно.&lt;br /&gt;Запомните: Если вы еще не ознакомились с нашей &quot;подложкой&quot; для кода приложения, позже вам лучше посмотреть &lt;a href=&quot;http://extjs.com/learn/Tutorial:Application_Layout_for_Beginners&quot;&gt;учебник по Подложке (Структуре) Приложений&lt;/a&gt; сделаный Jozef Sakalos.&lt;br /&gt;Давайте определим наши поля вначале скрипта:&lt;br /&gt; &lt;pre&gt;  var FirstNameField;&lt;br /&gt;  var LastNameField;&lt;br /&gt;  var EnteringOfficeField;&lt;br /&gt;  var LeavingOfficeField;&lt;br /&gt;  var IncomeField;&lt;br /&gt;  var PartyField;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Нам нужно написать код  который описывает назначения каждого поля: (внутри функции onReady):&lt;br /&gt;&lt;pre&gt;  FirstNameField = new Ext.form.TextField({&lt;br /&gt;    id: &#39;FirstNameField&#39;,&lt;br /&gt;    fieldLabel: &#39;First Name&#39;,&lt;br /&gt;    maxLength: 20,&lt;br /&gt;    allowBlank: false,&lt;br /&gt;    anchor&amp;nbsp;: &#39;95%&#39;,&lt;br /&gt;    maskRe: /([a-zA-Z0-9\s]+)$/&lt;br /&gt;      });&lt;br /&gt;      &lt;br /&gt;  LastNameField = new Ext.form.TextField({&lt;br /&gt;    id: &#39;LastNameField&#39;,&lt;br /&gt;    fieldLabel: &#39;Last Name&#39;,&lt;br /&gt;    maxLength: 20,&lt;br /&gt;    allowBlank: false,&lt;br /&gt;    anchor&amp;nbsp;: &#39;95%&#39;,    &lt;br /&gt;    maskRe: /([a-zA-Z0-9\s]+)$/  &lt;br /&gt;      });&lt;br /&gt;  &lt;br /&gt;  EnteringOfficeField = new Ext.form.DateField({&lt;br /&gt;    id:&#39;EnteringOfficeField&#39;,&lt;br /&gt;    fieldLabel: &#39;Entering Office&#39;,&lt;br /&gt;    format&amp;nbsp;: &#39;m/d/Y&#39;,&lt;br /&gt;    allowBlank: false,&lt;br /&gt;    anchor:&#39;95%&#39;&lt;br /&gt;    });&lt;br /&gt;    &lt;br /&gt;  LeavingOfficeField = new Ext.form.DateField({&lt;br /&gt;    id:&#39;LeavingOfficeField&#39;,&lt;br /&gt;    fieldLabel: &#39;Leaving Office&#39;,&lt;br /&gt;    allowBlank: false,&lt;br /&gt;    format&amp;nbsp;: &#39;m/d/Y&#39;,&lt;br /&gt;    anchor:&#39;95%&#39;&lt;br /&gt;    });&lt;br /&gt;  &lt;br /&gt;  IncomeField = new Ext.form.NumberField({&lt;br /&gt;    id:&#39;IncomeField&#39;,&lt;br /&gt;    fieldLabel: &#39;Income&#39;,&lt;br /&gt;    allowNegative: false,&lt;br /&gt;    allowBlank: false,&lt;br /&gt;    anchor:&#39;95%&#39;&lt;br /&gt;    });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Все очень просто и понятно. Теперь у нас есть поля... Вам нравится? Запомните, что поле должно быть связано с данными в SQL таблице. В 3 Части мы говорили об этом при использовании DataStore. В 4 части мы видим три различных варианта заполнения нашего выпадающего списка.&lt;br /&gt;В этой части учебника мы продолжим использование SimpleStore. Вам следует держать в памяти, что заполнение нашего списка из предопределенного HTML списка может создать некоторые проблемы совместимости броузера (я подумал о бедных пользователях IE немножко...)&lt;br /&gt;&lt;pre&gt;  PartyField = new Ext.form.ComboBox({&lt;br /&gt;     id:&#39;PartyField&#39;,&lt;br /&gt;     fieldLabel: &#39;Party&#39;,&lt;br /&gt;     store:new Ext.data.SimpleStore({&lt;br /&gt;       fields:[&#39;partyValue&#39;, &#39;partyName&#39;],&lt;br /&gt;       data: [[&#39;1&#39;,&#39;No Party&#39;],[&#39;2&#39;,&#39;Federalist&#39;],[&#39;3&#39;,&#39;Democratic-Republican&#39;],[&#39;4&#39;,&#39;Democratic&#39;],[&#39;5&#39;,&#39;Whig&#39;],[&#39;6&#39;,&#39;Republican&#39;]]&lt;br /&gt;       }),&lt;br /&gt;     mode: &#39;local&#39;,&lt;br /&gt;     displayField: &#39;partyName&#39;,&lt;br /&gt;     allowBlank: false,&lt;br /&gt;     valueField: &#39;partyValue&#39;,&lt;br /&gt;     anchor:&#39;95%&#39;,&lt;br /&gt;     triggerAction: &#39;all&#39;&lt;br /&gt;      });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Создание формы&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Теперь все поля созданы и готовы, надо создать форму для них:&lt;br /&gt;&lt;pre&gt;  PresidentCreateForm = new Ext.FormPanel({&lt;br /&gt;        labelAlign: &#39;top&#39;,&lt;br /&gt;        bodyStyle:&#39;padding:5px&#39;,&lt;br /&gt;        width: 600,        &lt;br /&gt;        items: [{&lt;br /&gt;            layout:&#39;column&#39;,&lt;br /&gt;            border:false,&lt;br /&gt;            items:[{&lt;br /&gt;                columnWidth:0.5,&lt;br /&gt;                layout: &#39;form&#39;,&lt;br /&gt;                border:false,&lt;br /&gt;                items: [FirstNameField, LastNameField, PartyField]&lt;br /&gt;            },{&lt;br /&gt;                columnWidth:0.5,&lt;br /&gt;                layout: &#39;form&#39;,&lt;br /&gt;                border:false,&lt;br /&gt;                items: [EnteringOfficeField, LeavingOfficeField, IncomeField]&lt;br /&gt;            }]&lt;br /&gt;        }],&lt;br /&gt;    buttons: [{&lt;br /&gt;      text: &#39;Save and Close&#39;,&lt;br /&gt;      handler: createThePresident&lt;br /&gt;    },{&lt;br /&gt;      text: &#39;Cancel&#39;,&lt;br /&gt;      handler: function(){&lt;br /&gt;        // because of the global vars, we can only instantiate one window... so let&#39;s just hide it.&lt;br /&gt;        PresidentCreateWindow.hide();&lt;br /&gt;      }&lt;br /&gt;    }]&lt;br /&gt;    });&lt;br /&gt;  &lt;br /&gt;  PresidentCreateWindow= new Ext.Window({&lt;br /&gt;      id: &#39;PresidentCreateWindow&#39;,&lt;br /&gt;      title: &#39;Creating a New President&#39;,&lt;br /&gt;      closable:true,&lt;br /&gt;      width: 610,&lt;br /&gt;      height: 250,&lt;br /&gt;      plain:true,&lt;br /&gt;      layout: &#39;fit&#39;,&lt;br /&gt;      items: PresidentCreateForm&lt;br /&gt;    });&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ок... неплохо да? Недо запомнить одну важную вещь, то что каждый вложенный элемент имеет поле layout (подложка). Не забудьте его, так как это тема множества топиков на форумах... Ну хорошо, теперь у нас есть отличная форма. До того, как мы ее покажем, нам нужно перехватывать события кнопок и создать функции для каждого из них для сохранения данных. Хорошая штука в том, что мы так создали форму в том мы можем напрямую получать значения полей с помощью методов setValue() или getValue().&lt;br /&gt;&lt;br /&gt;Давайте сначала создадим небольшие функции для работы с формой.&lt;br /&gt;&lt;pre&gt;  // reset the Form before opening it&lt;br /&gt;  function resetPresidentForm(){&lt;br /&gt;    FirstNameField.setValue(&#39;&#39;);&lt;br /&gt;    LastNameField.setValue(&#39;&#39;);&lt;br /&gt;    EnteringOfficeField.setValue(&#39;&#39;);&lt;br /&gt;    LeavingOfficeField.setValue(&#39;&#39;);&lt;br /&gt;    IncomeField.setValue(&#39;&#39;);&lt;br /&gt;    PartyField.setValue(&#39;&#39;);    &lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  // check if the form is valid&lt;br /&gt;  function isPresidentFormValid(){&lt;br /&gt;  return(FirstNameField.isValid() &amp;amp;&amp;amp; LastNameField.isValid() &amp;amp;&amp;amp; EnteringOfficeField.isValid() &amp;amp;&amp;amp; LeavingOfficeField.isValid() &amp;amp;&amp;amp; IncomeField.isValid() &amp;amp;&amp;amp; PartyField.isValid());&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  // display or bring forth the form&lt;br /&gt;  function displayFormWindow(){&lt;br /&gt;  if(!PresidentCreateWindow.isVisible()){&lt;br /&gt;    resetPresidentForm();&lt;br /&gt;    PresidentCreateWindow.show();&lt;br /&gt;  } else {&lt;br /&gt;    PresidentCreateWindow.toFront();&lt;br /&gt;  }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Создание президента&lt;/span&gt;&lt;br /&gt;Теперь нам нужно реализовать метод сохранения. Вы найдете его достаточно простым по сравнению с тем, что мы делали при редактировании ячеек:&lt;br /&gt;&lt;pre&gt;  function createThePresident(){&lt;br /&gt;     if(isPresidentFormValid()){&lt;br /&gt;      Ext.Ajax.request({   &lt;br /&gt;        waitMsg: &#39;Please wait...&#39;,&lt;br /&gt;        url: &#39;database.php&#39;,&lt;br /&gt;        params: {&lt;br /&gt;          task: &quot;CREATEPRES&quot;,&lt;br /&gt;          firstname:      FirstNameField.getValue(),&lt;br /&gt;          lastname:       LastNameField.getValue(),&lt;br /&gt;          enteringoffice: EnteringOfficeField.getValue().format(&#39;Y-m-d&#39;),&lt;br /&gt;          leavingoffice:  LeavingOfficeField.getValue().format(&#39;Y-m-d&#39;),&lt;br /&gt;          income:         IncomeField.getValue(),&lt;br /&gt;          party:          PartyField.getValue()&lt;br /&gt;        }, &lt;br /&gt;        success: function(response){              &lt;br /&gt;          var result=eval(response.responseText);&lt;br /&gt;          switch(result){&lt;br /&gt;          case 1:&lt;br /&gt;            Ext.MessageBox.alert(&#39;Creation OK&#39;,&#39;The president was created successfully.&#39;);&lt;br /&gt;            PresidentsDataStore.reload();&lt;br /&gt;            PresidentCreateWindow.hide();&lt;br /&gt;            break;&lt;br /&gt;          default:&lt;br /&gt;            Ext.MessageBox.alert(&#39;Warning&#39;,&#39;Could not create the president.&#39;);&lt;br /&gt;            break;&lt;br /&gt;          }        &lt;br /&gt;        },&lt;br /&gt;        failure: function(response){&lt;br /&gt;          var result=response.responseText;&lt;br /&gt;          Ext.MessageBox.alert(&#39;error&#39;,&#39;could not connect to the database. retry later&#39;);          &lt;br /&gt;        }                      &lt;br /&gt;      });&lt;br /&gt;    } else {&lt;br /&gt;      Ext.MessageBox.alert(&#39;Warning&#39;, &#39;Your Form is not valid!&#39;);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Отлично... Это было неплохо, да? Теперь все что нам нужно это каким-нибудь образом вызывать displayFormWindow(). Мы можем делать это через контекстное меню (правый клик) который опишем позже, или мы можем сделать это с помощью панели инструментов. Давайте сделаем эту панель:&lt;br /&gt;Нам просто нужно добавить следующее в наш конструктор EditorGrid:&lt;br /&gt;&lt;pre&gt;      tbar: [{&lt;br /&gt;         text: &#39;Add a president&#39;,&lt;br /&gt;  tooltip: &#39;Great Tooltip&#39;,&lt;br /&gt;         iconCls:&#39;add&#39;,    // this is defined in our styles.css&lt;br /&gt;         handler: displayFormWindow&lt;br /&gt;      }]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Последние штрихи&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Отлично. Мы еще не все сделали. Нам нужна серверная обработка запроса CREATEPRES.&lt;br /&gt;Идем в файл database.php и вставим ее:&lt;br /&gt;В выборе:&lt;br /&gt;&lt;pre&gt;    case &quot;CREATEPRES&quot;:&lt;br /&gt;        createPresident();&lt;br /&gt;        break;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;И напишем саму функцию:&lt;br /&gt;&lt;pre&gt;function createPresident(){&lt;br /&gt;&lt;br /&gt; $firstname = addslashes($_POST[&#39;firstname&#39;]);&lt;br /&gt; $lastname = addslashes($_POST[&#39;lastname&#39;]);&lt;br /&gt; $enteringoffice = $_POST[&#39;enteringoffice&#39;];&lt;br /&gt; $leavingoffice = $_POST[&#39;leavingoffice&#39;];&lt;br /&gt; $income = $_POST[&#39;income&#39;];&lt;br /&gt; $party  = $_POST[&#39;party&#39;];&lt;br /&gt;&lt;br /&gt; // Here we should probably do some database checking, to make sure that we do not have the same entry twice for ex... And we would return a different error code (ECHO &#39;0&#39; or whatever you want...) For now we&#39;ll pretend like the entry is valid. &lt;br /&gt; $query = &quot;INSERT INTO presidents (`IDpresident` ,`IDparty` ,`firstname` ,`lastname` ,`tookoffice` ,`leftoffice` ,`income` ) VALUES (NULL , &#39;$party&#39;, &#39;$firstname&#39;, &#39;$lastname&#39;, &#39;$enteringoffice&#39;, &#39;$leavingoffice&#39;, &#39;$income&#39;)&quot;;&lt;br /&gt; $result = mysql_query($query);&lt;br /&gt; echo &#39;1&#39;;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Вот теперь вы можете добавлять президентов в вашу таблицу.&lt;br /&gt;&lt;br /&gt;Что надо запомнить из этой части:&lt;br /&gt;-Обязательно про SimpleStore&lt;br /&gt;&lt;br /&gt;Файлы этой части учебника &lt;a href=&quot;http://nicolas.bize.free.fr/ext/tutorial/Tutorial%20Part%205.zip&quot;&gt;доступны здесь&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Иточник: &lt;a href=&quot;http://extjs.com/learn/Tutorial:Grid_PHP_SQL_Part5&quot;&gt;http://extjs.com/learn/Tutorial:Grid_PHP_SQL_Part5&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlibs.blogspot.com/feeds/1153689412130691310/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-5.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1153689412130691310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/992119016619597159/posts/default/1153689412130691310'/><link rel='alternate' type='text/html' href='http://jlibs.blogspot.com/2008/12/grid-php-sql-5.html' title='Учебник: Grid PHP SQL Часть 5'/><author><name>Maks Zinchenko</name><uri>http://www.blogger.com/profile/14375286256340576283</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHdY3B4mq8krItqNOzvfwx725CcVN0wMur5zidjYsgdt4ACw6OHUTpEfJ7Ufe1CJY7hUQwsO25tvbvdVAKAbUXmt_VYeE16n8rYZ1Rmpd8H4YSRk5X6H8q-MZZQ-hqQ/s96/*'/></author><thr:total>0</thr:total></entry></feed>