Editor

С каждым годом увеличивается число приложений, использующих возможность редактирования текста со сложным форматированием. Можно даже сказать, что если приложение, имея привлекательный интерактивный интерфейс, вдруг предоставляет пользователю обычный элемент textarea (пусть даже диджит Textarea), это будет восприниматься, по меньшей мере, как нечто неестественное. К счастью, диджит Editor обладает типичной функциональностью по редактированию текста со сложным форматированием, а его использование не требует от вас приложения чрезмерных усилий.

Инструментарий Dojo опирается на использование элементов управления, реализованных в самом броузере, позволяющих редактировать содержимое. В качестве короткого экскурса в историю: в Internet Explorer 4.0 была реализована концепция режима разработки (designmode), в котором стало возможным редактировать текст способом, напоминающим простой редактор текста со сложным форматированием. Вслед за Microsoft в Mozilla 1.3 был также реализован практически идентичный прикладной программный интерфейс, который в конечном итоге был формализован в виде спецификации Midas Specification (http://www.mozilla.org/editor/midas!spec.html). Другие броузеры тоже последовали в этом направлении, хотя и с некоторыми незначительными отклонениями. В любом случае, самое тяжелое – это сначала сделать документ редактируемым, а потом вызвать JavaScript-функцию execCommand, чтобы создать фактическую разметку. Следуя спецификации Midas Specification, поставленную задачу могли бы решить следующие строки программного кода:

// Сделать узел редактируемым... это может быть div с установленной
// шириной и высотой
document.getElementById("foo").contentDocument.designMode="on";
/* Выделить некоторый текст... */
// Придать выделенному тексту курсивное начертание.
// Никаких дополнительных аргументов не требуется.
editableDocument.execCommand("Italic", false, null);


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

Пример 15.12. Пример типичного использования диджита Editor
<div style="margin:5px;background:#eee; height: 400px; width:525px">
<div id="editor" height="375px" dojoType="dijit.Editor">
When shall we three meet again?

In thunder, lightning, or in rain?
</div>
</div>
(button dojoType="dijit.form.Button")Save
<script type="dojo/method" event="onClick" args="evt">
/* Сохраните содержимое редактора любым способом по вашему выбору */
console.log(dijit.byId("editor").getValue());
</script>
(/button)
(button dojoType="dijit.form.Button")Clear
<script type="dojo/method" event="onClick" args="evt">
dijit.byId("editor").replaceValue("");
</script>
(/button)


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

Добавлено: 25 Июля 2018 07:33:07 Добавил: Андрей Ковальчук

Пример реализации операции «перетащил и бросил» в дереве

Эти методы являются настолько общими, что они могут передаваться диджиту Tree на этапе конструирования, что особенно замечательно, так как позволяет максимально использовать существующую реализацию в dijit._tree. Теперь настало время для еще одного примера.

Возьмем за основу пример 15.9 и дополним его возможностью перемещать элементы дерева мышью. Чтобы минимизировать прилагаемые для этого усилия, будем опираться на шаблонную реализацию dijit._tree. Кроме того, обратите внимание, что нам придется отказаться от механизма ItemFileReadStore и задействовать ItemFileWriteStore, так как сама природа операции перетаскивания не предполагает доступ только для чтения.

Чтобы пример не противоречил здравому смыслу, нам необходимо предотвратить возможность сброса элементов на другие элементы, так как элементы по своей сути отличаются от категорий элементов, как мы их определили в уже описанном ранее хранилище dojo.data. Реализация приводится в примере 15.11.
Пример 15.11. Простое дерево с возможностью перетаскивания элементов

<html>
<head>
<title>Drag and Droppable Tree Fun!</title>
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" />
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"
djConfig="parseOnLoad:true,isDebug:true">
</script>
<script type="text/javascript">
dojo.require("dijit.Tree");
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dijit._tree.dndSource");
dojo.require("dojo.parser");
dojo.addOnLoad(function() {
//связать обработчик checkItemAcceptance...
dijit.byId("tree").checkItemAcceptance = function(target,
source) {
//преобразовать цель (узел DOM) в узел дерева
//и затем получить элемент данных
var item = dijit.getEnclosingWidget(target).item;
//запретить сброс в корневой (сфабрикованный) узел
//и не допускать сброс на элементы, не являющиеся
//категориями
return (item.id != "root" && item.type == "category");
}
});
</script>
</head>
(body class="tundra")
<div dojoType="dojo.data.ItemFileWriteStore" jsId="dataStore"
url="./programmingLanguages.json"></div>
<div dojoType="dijit.tree.ForestStoreModel" jsId="model"
store="dataStore" query="{type:'category'}" rootId="root"
rootLabel="Programming Languages"></div>
<div id="tree" dojoType="dijit.Tree" model="model"
dndController="dijit._tree.dndSource"></div>
(/body)
</html>


Когда у вас появится потребность реализовать возможность перетаскивания элементов внутри диджита Tree, стоит потратить некоторое время на изучение шаблонной реализации в dijit._tree. Любой случай применения механизма перетаскивания обычно имеет свои особенности, поэтому вероятность найти готовое решение, не требующее приложения дополнительных усилий, близка к нулю.

Добавлено: 25 Июля 2018 07:32:26 Добавил: Андрей Ковальчук

Реакция на событие щелчка мышью

Иметь возможность отображения данных в виде дерева хорошо уже само по себе, но разве не было бы еще лучше иметь возможность обрабатывать такие события, как щелчок мышью? Давайте реализуем точку расширения onClick, чтобы продемонстрировать возможность обрабатывать щелчки мышью на различных элементах. В функцию onClick для обработки передаются как сам узел _TreeNode, на котором произошел щелчок, так и элемент данных dojo.data. В примере 15.10 показаны изменения, которые необходимо внести, чтобы реализовать обработку щелчка.
Пример 15.10. Обработка щелчков мышью в диджите Tree

(body class="tundra")
<div dojoType="dojo.data.ItemFileReadStore" jsId="dataStore"
url="./programmingLanguages.json"></div>
<div dojoType="dijit.tree.ForestStoreModel" jsId="model" store="dataStore"
query="{type:'category'}" rootId="root"
rootLabel="Programming Languages"></div>
<div dojoType="dijit.Tree" model="model" >
<script type="dojo/method" event="onClick" args="item,treeNode">
//использовать элемент данных или узел по желанию...
console.log("onClick:",dataStore.getLabel(item)); //вывести метку
</script>
</div>
(/body)


Обратите внимание: несмотря на наличие между Tree и dojo.data промежуточной модели, обеспечивающей дополнительный уровень абстракции данных, мы попрежнему имеем возможность прямого доступа к элементам данных. Здесь нет никакой необходимости использовать промежуточную модель, которая упрощает возможность отображения данных, но является совершенно ненужной прослойкой между элементом dojo.data и обычными средствами доступа к нему.

Добавлено: 25 Июля 2018 07:31:46 Добавил: Андрей Ковальчук

Простой лес

Во многих приложениях используются данные, для представления которых необходимо несколько корневых узлов, поэтому скорректируем предыдущий пример так, чтобы он работал с лесом, а не с деревом, и можно было бы заметить различия между подходами. Для начала нам необходимы данные, имеющие несколько корневых узлов. Взгляните на следующий пример, где языки программирования перечислены в виде леса, полученного в результате исключения корневого узла «programming languages» (языки программирования):

{
identifier : 'name',
label : 'name',
items : [
{
name : 'Object-Oriented',
type : 'category',
children: [
{name : 'JavaScript', type : 'language'},
{name : 'Java', type : 'language'},
{name : 'Ruby', type : 'language'}
]
},
{
name : 'Imperative',
type : 'category',
children: [
{name : 'C', type : 'language'},
{name : 'FORTRAN', type : 'language'},
{name : 'BASIC', type : 'language'}
]
},
{
name : 'Functional',
type : 'category',
children: [
{name : 'Lisp', type : 'language'},
{name : 'Erlang', type : 'language'},
{name : 'Scheme', type : 'language'}
]
}
]
}


Как видите, в измененных данных, представленных в формате JSON, отсутствует единый корневой узел, поэтому такие данные можно представить только в виде леса. Единственное существенное изменение по сравнению с примером 15.7 заключается в необходимости добавления в диджит Tree параметра showRoot, чтобы скрыть его корень; в изменении запроса, чтобы идентифицировать узлы верхнего уровня, и в замене TreeStoreModel на ForestStoreModel. В примере 15.8 приводится измененный код разметки, в котором различия выделены жирным шрифтом.

Пример 15.8. Изменения, необходимые для представления данных не в виде дерева, а в виде леса
(body class="tundra")
<div dojoType="dojo.data.ItemFileReadStore" jsId="dataStore"
url="./programmingLanguages.json"></div>
<div dojoType="dijit.tree.ForestStoreModel" jsId="model" store="dataStore"
query="{type:'category'}"></div>
<div dojoType="dijit.Tree" model="model" showRoot=false></div>
(/body)


То, что данные имеют структуру, которую можно отобразить как лес, еще не означает, что их нельзя отобразить в виде дерева. В примере 15.9 демонстрируется, как в данных, получаемых с помощью механизмов dojo.data, можно сфабриковать корневой узел с помощью атрибутов rootId и rootLabel в ForestStoreModel.
Пример 15.9. Изменения, создающие корневой узел,
чтобы лес выглядел как дерево
(body class="tundra")
<div dojoType="dojo.data.ItemFileReadStore" jsId="dataStore"
url="./programmingLanguages.json"></div>
<div dojoType="dijit.tree.ForestStoreModel" jsId="model" store="dataStore"
query="{type:'category'}" rootId="root"
rootLabel="Programming Languages"></div>
<div dojoType="dijit.Tree" model="model" ></div>
(/body)


С практической точки зрения сфабрикованный корневой узел теперь может участвовать в операциях, выполняемых средствами интерфейса dojo.data, такими как getLabel и getValue. На первый взгляд в этом нет ничего особенного, но благодаря такому подходу теперь можно заниматься работой с данными, не отвлекаясь на необходимость обрабатывать особые случаи.

Добавлено: 25 Июля 2018 07:31:22 Добавил: Андрей Ковальчук

Простое дерево

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

dojo.data.ItemFileReadStore:
{
identifier : 'name',
label : 'name',
items : [
{
name : 'Programming Languages',
children: [
{name : 'JavaScript'},
{name : 'Python'},
{name : 'C++'},
{name : 'Erlang'},
{name : 'Prolog'}
]
}
]
}


Пока все просто. Чтобы на стороне клиента не выполнять разбор данных вручную, эту работу можно поручить dojo.data. Задействование механизма ItemFileReadStore выполняется очень просто, для этого достаточно указать URL источника данных и запросить эти данные. Приведенный далее тег, после того как он будет проанализирован парсером, мог бы справиться с этой задачей – при условии, что в рабочем каталоге присутствует файл с данными, который называется program!
mingLanguages.json, а сам диджит имеет глобальный идентификатор
dataStore, обеспечивающий доступ к нему:
<div dojoType="dojo.data.ItemFileReadStore"
jsId="dataStore" url="./programmingLanguages.json"></div>

Однако, прежде чем данные попадут в диджит Tree, их необходимо передать промежуточному звену – TreeStoreModel. (К использованию ForestStoreModel мы подойдем чуть ниже.) Полный перечень особенностей, составляющих прикладной программный интерфейс TreeStoreModel, будет представлен немного ниже, а пока достаточно будет знать, что в TreeStoreModel следует настроить ссылку на ItemFileReadStore и определить текст запроса. Следующий диджит TreeStoreModel обращается к механизму dojo.data с глобальным идентификатором dataStore за получением всех значений атрибута name:
<div dojoType="dijit.tree.TreeStoreModel" jsId="model" store="dataStore"
query="{name:'*'}"></div>

Теперь единственное, что осталось сделать, – это определить ссылку на TreeStoreModel внутри диджита Tree, как показано ниже:
<div dojoType="dijit.Tree" model="model"></div>

Пример 15.7. Простое дерево с одним корневым узлом
<html>
<head>
<title>Tree Fun!</title>
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" />
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"
djConfig="parseOnLoad:true,isDebug:true">
</script>
<script type="text/javascript">
dojo.require("dijit.Tree");
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dojo.parser");
</script>
</head>
(body class="tundra")
<div dojoType="dojo.data.ItemFileReadStore" jsId="dataStore"
url="./programmingLanguages.json"></div>
<div dojoType="dijit.tree.TreeStoreModel" jsId="model"
store="dataStore" query="{name:'*'}"></div>
<div dojoType="dijit.Tree" model="model"></div>
(/body)
</html>

Добавлено: 25 Июля 2018 07:30:50 Добавил: Андрей Ковальчук

InlineEditBox

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

В простейшем случае можно просто обернуть TextBox диджитом InlineEditBox, сделав его, например, частью шаблона письма, как показано в следующем примере. Обратите внимание, что та часть, которая должна была бы отображаться как TextBox и загромождала бы изображение, выглядит как обычная разметка, но после щелчка мышью преобразуется в элемент редактирования:

Dear <span dojoType="dijit.InlineEditBox" autoSave="false"
editor="dijit.form.TextBox">Valued Customer</span>:
<div>We have received your request to be removed from our spam list. Not to worry, we'll remove you when we’re good and ready. In the meanwhile, please do not hesitate to contact us with further complaints.</div>
<div>Sincerely,</div>
<span dojoType="dijit.InlineEditBox" autosave="false"
editor="dijit.form.TextBox">Customer Service</span>


В этом примере атрибут autosave устанавливается в значение false, благодаря чему в элементе управления появляются две кнопки Сохранить (Save)1 и Отменить (Cancel) (в противном случае текст сохранялся бы автоматически по мере набора и эти кнопки вообще не отображались бы). Это очень важно. Теперь попробуем расширить базовую концепцию и создадим другой шаблон для составления письма.

Ниже приводится короткий пример, где диджитом InlineEditBox обернут диджит Textarea. Обратите внимание, что атрибут renderAsHtml позволяет отображать и редактировать исходный текст разметки:
Dear <span dojoType="dijit.InlineEditBox" autoSave="false"
editor="dijit.form.TextBox">Valued Customer</span>:
<div dojoType="dijit.InlineEditBox" autoSave="false"
editor="dijit.form.Textarea" renderAsHtml="true">
Insert(br)
Form(br)
Letter(br)
Here(br)
</div>
<div>Sincerely,</div>
<span dojoType="dijit.InlineEditBox"
autoSave="false" editor="dijit.form.TextBox">Customer Service</span>


Как и для других диджитов, рассматривавшихся выше в этой главе, типичное использование InlineEditBox не вызывает сложностей.

Добавлено: 25 Июля 2018 07:29:46 Добавил: Андрей Ковальчук

TitlePane

TitlePane – это виджет, который всегда отображает заголовок, но его тело может разворачиваться или сворачиваться по мере необходимости. Фактическое изменение размера виджета сопровождается анимационным эффектом. Будучи наследником ContentPane, диджит TitlePane имеет доступ ко всем унаследованным методам загрузки удаленного содержимого, хотя явно они в этом разделе не рассматриваются. В примере 15.5 демонстрируется типичное использование TitlePane.
Пример 15.5. Пример типичного использования диджита TitlePane

<div dojoType="dijit.TitlePane" title="Grocery list:" style="width:300px">
<ul>
<li>Eggs</li>
<li>Milk</li>
<li>Bananas</li>
<li>Coffee</li>
</ul>
</div>


Виджет TitlePane может использоваться как простой статический элемент страницы, однако ему можно найти более интересное применение – как более интерактивному элементу управления. В следующем примере демонстрируется использование TitlePane в качестве имитации стикеров с примечанием, которые можно увидеть во многих приложениях. Для этого вполне достаточно просто вставить такой виджет, как Textarea, внутрь TitlePane и изменять заголовок всякий раз, когда последний из них закрывается, как показано в примере 15.6.
Пример 15.6. Имитация стикера с примечанием с помощью TitlePane dojo.addOnLoad(function() {
var ed = new dijit.form.Textarea({id : "titlePaneContent"});
dijit.byId("tp").setContent(ed.domNode);
});
// А теперь диджит TitlePane, который можно объявить в разметке:
<div id="tp" dojoType="dijit.TitlePane" style="width:300px">
<script type="dojo/connect" event="toggle">
if (!this.open) {
var t = dijit.byId("titlePaneContent").getValue();
if (t.length > 15)
t = t.slice(0,12)+"...";
this.setTitle(t);
}
</script>
</div>


Дополнительная стилизация и возможность перетаскивания объектов мышью – это практически все, что необходимо для создания небольшого приложения для работы с такого рода заметками.

Добавлено: 25 Июля 2018 07:29:15 Добавил: Андрей Ковальчук

Menu

Диджит Menu моделирует контекстное меню, подобное тому, что появляется, если щелкнуть правой кнопкой мыши на ярлыке приложения или на поверхности рабочего стола. Диджит Menu содержит в себе виджеты MenuItem, являющиеся обычными пунктами меню, которые можно выбирать, или виджеты PopupMenuItem, образующие еще один слой элементов меню (напоминая меню кнопки Пуск (Start) в операционной системе Windows). Дочерним для PopupMenuItem является другой диджит Menu. Теоретически с помощью диджитов PopupMenuItem и MenuItem можно было бы реализовать иерархические меню любой степени вложенности, хотя такое решение нельзя назвать мудрым с точки зрения простоты и удобства.

Для начала рассмотрим простое меню, состоящее только из диджитов MenuItem, как показано в примере 15.4.
Пример 15.4. Пример типичного использования диджита Menu

(body class="tundra")
<!-- щелчок правой кнопкой мыши здесь приводит к появлению контекстного меню -->
<div id="context" style="background:#eee; height:300px;
width:300px;"></div>
<div dojoType="dijit.Menu" targetNodeIds="context" style="display:none">
<div dojoType="dijit.MenuItem">foo
<script type="dojo/method" event="onClick" args="evt">
console.log("foo");
</script>
</div>
<div dojoType="dijit.MenuItem">bar
<script type="dojo/method" event="onClick" args="evt">
console.log("bar");
</script>
</div>
<div dojoType="dijit.MenuItem">baz
<script type="dojo/method" event="onClick" args="evt">
console.log("baz");
</script>
</div>
</div>
(/body)


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

Теперь предположим, что нам необходимо, чтобы пункт baz был реализован диджитом PopupMenuItem, а само меню было бы контекстным для всего окна. Сделать это можно, как показано ниже:
<div dojoType="dijit.Menu" style="display:none"
contextualMenuForWindow="true">
<div dojoType="dijit.MenuItem">foo
<script type="dojo/method" event="onClick" args="evt">
console.log("foo");
</script>
</div>
<div dojoType="dijit.MenuItem">bar
<script type="dojo/method" event="onClick" args="evt">
console.log("bar");
</script>
</div>
<div dojoType="dijit.PopupMenuItem">
<span>baz</span>
<div dojoType="dijit.Menu">
<!YY определить обработчики события onClick
для каждого элемента YY>
<div dojoType="dijit.MenuItem">yabba</div>
<div dojoType="dijit.MenuItem">dabba</div>
<div dojoType="dijit.MenuItem">doo</div>
</div>
</div>
</div>


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

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

Добавлено: 25 Июля 2018 07:28:43 Добавил: Андрей Ковальчук

Toolbar

Панель инструментов – это еще один хорошо знакомый элемент управления, который упрощает доступ пользователя к наиболее часто используемым командам. Проще говоря, диджит Toolbar (панель инструментов) представляет собой всего лишь место для размещения коллекции диджитов Button, которые при соответствующей стилизации могут
иметь весьма привлекательный внешний вид. В состав библиотеки Dijit входят различные предопределенные темы, содержащие классы для многих распространенных операций, таких как вырезать/вставить, жирный/курсив и прочих, которые можно указывать в качестве значения атрибута iconClass диджитов Button.

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

<html>
<head>
<title>Fun with Toolbar!</title>
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" />
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"
djConfig="parseOnLoad:true,isDebug:true">
</script>
<script type="text/javascript">
dojo.require("dojo.parser");
dojo.require("dijit.Toolbar");
dojo.require("dijit.form.Button");
dojo.addOnLoad(function() {
var bold = function() {console.log("bold");}
var italic= function() {console.log("italic");}
var underline = function() {console.log("underline");}
var superscript = function() {console.log("superscript");}
var subscript = function() {console.log("subscript");}
dojo.query(".dijitEditorIcon").forEach(function(x) {
if (dojo.hasClass(x, "dijitEditorIconBold"))
dojo.connect(x.parentNode, "onclick", bold);
else if (dojo.hasClass(x, "dijitEditorIconItalic"))
dojo.connect(x.parentNode, "onclick", italic);
else if (dojo.hasClass(x, "dijitEditorIconUnderline"))
dojo.connect(x.parentNode, "onclick", underline);
else if (dojo.hasClass(x, "dijitEditorIconSubscript"))
dojo.connect(x.parentNode, "onclick", superscript);
else if (dojo.hasClass(x, "dijitEditorIconSuperscript"))
dojo.connect(x.parentNode, "onclick", subscript);
});
});
</script>
</head>
(body style="padding:100px" class="tundra")
<div dojoType="dijit.Toolbar" style="width:175px">
(button dojoType="dijit.form.Button"
iconClass="dijitEditorIcon dijitEditorIconBold" )(/button)
(button dojoType="dijit.form.Button"
iconClass="dijitEditorIcon dijitEditorIconItalic" )(/button)
(button dojoType="dijit.form.Button"
iconClass="dijitEditorIcon dijitEditorIconUnderline" )(/button)
<span dojoType="dijit.ToolbarSeparator"></span>
(button dojoType="dijit.form.Button"
iconClass="dijitEditorIcon dijitEditorIconSubscript")(/button)
(button dojoType="dijit.form.Button"
iconClass="dijitEditorIcon dijitEditorIconSuperscript")(/button)
</div>
(/body)
</html>


Интересно отметить, что в настоящее время библиотека Dijit определяет ряд наглядных ярлыков для редактора Editor (определения находятся в таблицах стилей темы), которые могут содержаться в диджите Toolbar.

Диджит Toolbar имеет простой прикладной программный интерфейс, который можно считать типичным для любого потомка класса _Container.

Добавлено: 25 Июля 2018 07:28:08 Добавил: Андрей Ковальчук

ColorPalette

ColorPalette – это еще один простой самостоятельный виджет, используемый для организации более наглядного и интерактивного способа выбора цвета, что может быть очень удобно в ситуациях, когда вы разрешаете пользователю настраивать тему приложения. По умолчанию палитра, заполненная предопределенными цветами, наиболее популярными в вебдизайне, может иметь два фиксированных размера: 3Н4
и 7Н10.

Использовать диджит ColorPalette в разметке очень просто, это показано в следующем листинге:

<div dojoType="dijit.ColorPalette">
<script type="dojo/method" event="onChange" args="selectedColor">
/* возможно, здесь же следует предусмотреть действия
по сокрытию палитры? */
console.log(selectedColor);
</script>
</div>


Создание диджита программным способом тоже выполняется достаточно просто:
var cp = new dijit.ColorPalette({/*здесь определяются атрибуты */});
/* Теперь следует добавить палитру в страницу...*/
dojo.body().appendChild(cp.domNode);

Добавлено: 25 Июля 2018 07:27:34 Добавил: Андрей Ковальчук

ProgressBar

Диджит ProgressBar, индикатор хода выполнения какойто операции, напоминает другие аналогичные индикаторы, которые можно встретить в приложениях, и предусматривает возможность работы в детерминированном и в недетерминированном режиме. Самое замечательное в этом диджите то, что о нем можно много не говорить. Фактически пример 15.3 прекрасно говорит сам за себя.

Пример 15.3. Типичный пример использования недетерминированного индикатора ProgressBar

<div dojoType="dijit.ProgressBar" indeterminate="true"
style="width:300px"></div>

Конечно, иногда вместо использования недетерминированного индикатора будет возникать необходимость получать данные от сервера и отображать фактический ход выполнения операции. Предположим, что у нас имеется серверная процедура, которая возвращает некоторое значение, свидетельствующее о ходе выполнения операции. Следующий фрагмент представляет собой модель такой процедуры:
import cherrypy
config = {
#передать этот статический файл...
'/foo.html' :
{
'tools.staticfile.on' : True,
'tools.staticfile.filename' : '/absolute/path/to/foo.html'
}
}
class Content:
def __init__(self):
self.progress = 0
@cherrypy.expose
def getProgress(self):
self.progress += 10
return str(self.progress)
cherrypy.quickstart(Content(), '/', config=config)


Файл foo.html, содержащий диджит ProgressBar, может выглядеть, как показано ниже:
<html>
<head>
<title>Fun with ProgressBar!</title>
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" />
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"
djConfig="parseOnLoad:true">
</script>
<script type="text/javascript">
dojo.require("dojo.parser");
dojo.require("dijit.ProgressBar");
dojo.addOnLoad(function() {
var progressInterval = setInterval(function() {
dojo.xhrGet({
url : "http://localhost:8080/getProgress",
load : function(response, ioArgs) {
console.log("load", response);
if (response <= 100) {
dijit.byId("pb").update(
{progress : response});
}
else {
clearInterval(progressInterval);
}
}
});
}, 1000);
});
</script>
</head>
(body style="padding:100px" class="tundra")
<div>Loading...</div>
<div id="pb" dojoType="dijit.ProgressBar" style="width:300px"></div>
(/body)
</html>


Функция addOnLoad в этом примере каждую секунду обращается к URL /getProgress, чтобы получить некоторое значение и с помощью функции update диджита ProgressBar использовать его для индикации хода выполнения операции. Применение функции setInterval вполне обычно при работе с ProgressBar.

Наконец напомню, что если потребуется отображать диджит ProgressBar при одновременном блокировании доступа к странице, чтобы заставить пользователя дождаться завершения операции, вы всегда можете поместить его внутрь диджита Dialog. Сделать это можно примерно так, как показано ниже:
var pb = new dijit.ProgressBar;
var d = new dijit.Dialog;
d.setContent(pb.domNode);
d.show();

Добавлено: 25 Июля 2018 07:27:10 Добавил: Андрей Ковальчук

TooltipDialog

Диджит TooltipDialog наследует Dialog, но предоставляемая им функциональность больше напоминает меню DropDownButton, за исключением того, что с этим диджитом вы можете взаимодействовать. Фактически в своем текущем проявлении TooltipDoalog мог бы размещаться в DropDownButton или ComboButton, хотя теоретически вы могли бы определить такой стиль кнопки, чтобы полностью изменить ее внешний вид. Можно считать, что концепция TooltipDialog предполагает порядок взаимодействия, который можно встретить в приложениях электронных таблиц.

Функциональные возможности TooltipDialog очень напоминают возможности диджита Dialog за исключением поддержки метода show(), что обуславливает невозможность использовать TooltipDialog в качестве самостоятельного диджита. Кроме того, он предоставляет стандарт ный атрибут title, который можно заполнить, если иметь в виду обеспечение высокого уровня доступности.

Хорошим примером использования TooltipDialog может служить интерактивное средство пометки изображения. Например, можно было бы использовать диджит DropDownButton для отображения картинок с помощью атрибута iconClass и реализовать TooltipDialog, который будет выводиться после щелчка мышью на изображении.

<!-- где-то там...
<style type="text/css">
.customImage {
background-image : url('/static/path/to/apple.jpeg');
backgrond-repeat : no-repeat;
width : 120px;
height : 120px;
}
</style>
-->
(button dojoType="dijit.form.DropDownButton" iconClass="customImage"
showLabel="false")
<span>This label is hidden...</span>
<div dojoType="dijit.TooltipDialog">
<span>Tag this image...<span>
<div dojoType="dijit.form.TextBox"></div>
</div>
(/button)

Добавлено: 25 Июля 2018 07:26:29 Добавил: Андрей Ковальчук

Tooltip

Всплывающие подсказки представляют собой замечательное средство обеспечения пользователя справочной информацией о назначении того или иного элемента управления, находящегося на странице. Обычный атрибут title языка разметки HTML неплохо подходил для приложений 1990х годов, но наступившая эра вебприложений требует наличия средств воспроизведения более богатого разнообразия подсказок. Диджит Tooltip как раз является таким средством, обеспечивая возможность отображения произвольной разметки HTML вместо простого фрагмента текста. В предыдущей главе вы уже встречались с диджитом Tooltip, когда рассматривали диджит ValidationTextBox и его наследников, теперь вы узнаете, что диджит Tooltip может использоваться самостоятельно.

Пример 15.1. Пример типичного использования диджита Tooltip

One <span id="one">fish</span>, two <span id="two">fish</span>.
<div dojoType="dijit.Tooltip" connectId="one,two">
A limbless cold-blooded vertebrate...<img src='./fish.jpeg'/>
</div>


Как было показано в примере, вы просто определяете произвольную разметку HTML, которая будет отображаться диджитом Tooltip, и больше ничего. Диджит Tooltip должен использоваться для отображения содержимого, доступного только для чтения, а для интерактивного содержимого, такого как поля ввода и кнопки, следует использовать диджит TooltipDialog, который будет представлен в следующем разделе.

Добавлено: 25 Июля 2018 07:25:09 Добавил: Андрей Ковальчук

AccordionContainer

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

Еще одно важная особенность AccordionContainer заключается в необходимости использовать специальный дочерний контейнер AccordionPane, который служит оберткой для всех его дочерних виджетов. Обсуждение фактических причин, объясняющих такое положение дел, не представляет особого интереса; достаточно знать, что это связано с внутренней реализацией AccordionContainer. Вообще достаточно воспринимать AccordionPane как ContentPane, и все будет в порядке.

В примере 14.8 демонстрируется простой виджет AccordionContainer в действии.
Пример 14.8. Создание диджита AccordionContainer в разметке

<div id="foo" dojoType="dijit.layout.AccordionContainer"
style="width:150px; height:150px; margin:5px">
<div dojoType="dijit.layout.AccordionPane" title="one">
<p>One fish...</p>
</div>
<div dojoType="dijit.layout.AccordionPane" title="two">
<p>Two fish...</p>
</div>
<div dojoType="dijit.layout.AccordionPane" title="red">
<p>Red fish...</p>
</div>
<div id="blue" dojoType="dijit.layout.AccordionPane" title="blue">
<div dojoType="dijit.layout.ContentPane" href="blueFish"></div>
</div>
</div>


Что касается прикладного интерфейса: сам диджит AccordionContainer предоставляет единственный дополнительный атрибут помимо тех, что предлагаются диджитом StackContainer.

Мы могли бы оставить реализацию примера создания диджита программным способом в качестве самостоятельного упражнения для тех, кому это интересно, однако в данном случае порядок создания, как показано в примере 14.9, несколько отличается от описанного ранее, потому что AccordionPane – это отдельный диджит.

Добавлено: 25 Июля 2018 07:24:13 Добавил: Андрей Ковальчук

TabContainer

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

<div dojoType="dijit.layout.TabContainer"
style="width:225px; height:100px; margin:5px; border:solid 1px;">
<div dojoType="dijit.layout.ContentPane" title="one">
One fish...
</div>
<div dojoType="dijit.layout.ContentPane" title="two">
Two fish...
</div>
<div dojoType="dijit.layout.ContentPane" title="red"
closable="true">Red fish...
<script type="dojo/method" event="onClose" args="evt">
console.log("Closing", this.title);
return true; //чтобы панель закрылась, следует вернуть true!
</script>
</div>
<div dojoType="dijit.layout.ContentPane" title="blue">
Blue fish...
</div>
</div>


Обратите особое внимание, что позиции вкладок устанавливаются автоматически – вам достаточно просто определить значение атрибута title для каждого дочернего виджета в TabContainer, а обо всем остальном позаботятся внутренние механизмы, не требуя от вас прямого вмешательства (и это лучшее решение). Кроме того, следует отметить, что вы можете сделать вкладки закрывающимися – с помощью атрибута closeable, а дополнительная точка расширения onClose позволит выполнить какиелибо действия при закрытии вкладки. Однако, будьте внимательны: чтобы вкладка закрылась, точка расширения onClose должна вернуть значение true.

Так же, как и в случае с диджитом StackContainer, в TabContainer можно реализовать отложенную загрузку содержимого, установив в виджетах ContentPane атрибут preload в значение false.

Пример 14.7. Создание диджита TabContainer программным способом var container = new
dijit.layout.TabContainer({
tabPosition: "left-h",
style : "width:200px;height:200px;"
}, "foo");
var leftChild = new dijit.layout.ContentPane({title : "tab1"});
leftChild.domNode.innerHTML="tab 1";
var rightChild = new dijit.layout.ContentPane({title : "tab2",
closable: true});
rightChild.domNode.innerHTML="tab 2";
container.addChild(leftChild);
container.addChild(rightChild);
container.startup();

Добавлено: 25 Июля 2018 07:23:51 Добавил: Андрей Ковальчук