Февраль 2011

Руководство по actionscript. часть 5, стр. 135

Ввод через текстовые поля

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

с вводом, выделением текста и гипертекстовыми ссылками. Информацию о фокусе ввода с клавиатуры, прокрутке и взаимодействию с мышью можно найти в гл. 22.

Ввод текста

Способность каждого текстового поля получать пользовательский ввод определяется значением переменной type этого поля. По умолчанию для текстовых полей, создаваемых с помощью кода на языке ActionScript, переменной экземпляра type присваивается значение TextFieldType. DYNAMIC — это значит, что текст может изменяться с помощью кода на языке ActionScript, при этом пользователь не может вносить изменения в текст. Чтобы текстовое поле могло получать пользовательский ввод, мы должны присвоить переменной type значение TextFieldType. INPUT, как показано в следующем коде:

var t:TextField = new TextField( ); t. type = TextFieldType. INPUT;

Когда переменной type объекта TextField присвоено значение TextFieldType. INPUT, пользователь может добавлять или удалять текст из этого текстового поля. Любые изменения, вносимые пользователем, автоматически отражаются переменными text и htmlText.

Чтобы получать уведомления о внесении пользователем изменений в текстовое поле, мы можем зарегистрировать в этом текстовом поле приемники для событий TextEvent. TEXT_INPUT и Event. CHANGE. Диспетчеризация события TextEvent. TEXT INPUT происходит в том случае, когда пользователь пытается изменить текст в текстовом поле, перед тем как будут обновлены значения переменных text и htmlText. Диспетчеризация события Event. CHANGE происходит после того, как в ответ на пользовательский ввод будут обновлены значения переменных text и htmlText. Подробную информацию по событиям TextEvent. TEXT_INPUT и Event. CHANGE можно найти в гл. 22.

По умолчанию пользователям не разрешается вводить разрывы строк в текстовые поля. Чтобы разрешить это (например, в результате нажатия клавиши Enter), присвойте переменной multiline значение true, как показано в следующем коде:

var t:TextField = new TextFi el d( ): t. type = TextFieldType. INPUT; t. multiline = true;

Чтобы ограничить набор символов, которые пользователь может вводить в текстовое поле, используйте переменную экземпляра restrict класса TextField. Например, следующее текстовое поле позволяет вводить только цифры, что может потребоваться для поля ввода номера кредитной карты:

var t:TextField = new TextFi el d( );

t. width = 200;

t. height = 20:

t. border = true;

t. background = true;

t. type = TextFieldType. INPUT;

t. restrict = «0-9″;

Чтобы ограничить количество символов, которое пользователь может ввести в текстовое поле, используйте переменную экземпляра maxChars класса TextField. Например, следующее текстовое поле позволяет ввести только восемь символов, что может потребоваться для поля ввода имени на форме регистрации:

var t:TextField = new TextField( ):

t. width = 100:

t. height = 20:

t. border = true:

t. background = true:

t. type = TextFieldType. INPUT:

t. maxChars = 8;

Для сокрытия всех вводимых символов с целью защиты экрана используйте переменную экземпляра displayAsPassword класса TextField. Когда переменной displayAsPas sword присвоено значение true, все символы отображаются в виде звездочек (*). Например, слова «hi there» отображаются в виде «********>>. Это позволяет пользователю вводить текст, не беспокоясь о том, что посторонний человек сможет его увидеть. Следующий код демонстрирует текстовое поле, которое скрывает символы, что может потребоваться для поля ввода пароля на форме регистрации:

var t:TextFi eld = new TextField( );

t. width = 100;

t. height = 20;

t. border = true;

t. background = true;

t. type = TextFieldType. INPUT;

t. displayAsPassword = true;

Форматирование пользовательского ввода. По умолчанию новый текст, вводимый пользователем, автоматически принимает форматирование символа, находящегося перед точкой вставки, или символа, находящегося в позиции 0, если новый текст добавляется перед этой позицией. Если поле было пустым, новый текст форматируется в соответствии с используемым по умолчанию форматом данного поля (который задается через переменную def aultTextFormat, как было рассмотрено ранее в разд. «Форматирование по умолчанию для текстовых полей» разд. «Форматирование текстовых полей»).

Руководство по actionscript. часть 5, стр. 136

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

1. Перехватите ввод с помощью события TextEvent. TEXT_INPUT.

2. Вручную добавьте эквивалентный текст.

3. Примените форматирование к тексту, вставленному вручную.

Эта методика продемонстрирована в листинге 27.21, представляющем пример класса FormattedlnputDemo. Понять код вам помогут комментарии.

Листинг 27.21. Форматирование пользовательского ввода

package { import flash. display.*; import flash. text.*; import flash. events.*;

public class FormattedInputDemo extends Sprite { public function FormattedlnputDemo ( ) { // Создаем объекты TextFormat var boldFormat-.TextFormat = new TextFormat( ); boldFormat. bold = true;

var italicFormat:TextFormat = new TextFormat( ); italicFormat. italic = true;

// Создаем текстовое поле

var t:TextField = new TextField( );

t. text = «lunchtime»;

// Форматируем слово «lunch» с использованием курсива t. setTextFormatUtalicFormat. 0. 5);

// Форматируем слово «time», используя полужирное начертание t. setTextFormat(boldFormat. 5. 9); t. type = TextFieldType. INPUT;

// Регистрируем приемник для событий TextEvent. TEXT_INPUT // в объекте t

t. addEventLi stener(TextEvent. TEXT_INPUT. textInputLi stener);

// Добавляем текстовое поле в список отображения addChild(t);

}

// Вызывается всякий раз. когда пользователь пытается добавить // новый текст в объект t

private function textlnputListener (e:TextEvent):void { // Получаем ссылку на текстовое поле, получившее ввод var t:TextField = TextField(e. target);

// Предотвращаем добавление текста, введенного пользователем // в текстовое поле e. preventDefault( );

// Добавляем текст, введенный пользователем вручную. В этом случае // происходит немедленное обновление переменной text объекта // TextField. позволяя нам отформатировать новый текст внутри // данной функции.

Руководство по actionscript. часть 5, стр. 137

T. replaceText(t. caretlndex. t. caretlndex. e. text):

// Устанавливаем форматирование для нового текста var regularFormat-.TextFormat = new TextFormat( ); regularFormat. bold = false; regularFormat. italic = false; t. setTextFormat(regularFormat.

t. caretlndex.

t. ca retIndex+e. text.1ength)

// Устанавливаем точку вставки в конец нового текста, чтобы // пользователь считал, что это он ввел текст

var newCaretIndex:int = t. caretlndex + e. text. length; t. setSelection(newCaretIndex, newCaretlndex);

}

}

}

Выделение текста

По умолчанию текст во всех текстовых полях, создаваемых программным путем, может быть выделен пользователем. Чтобы отключить возможность выделения для некоторого поля, присвойте переменной selectable значение false. Обычно выделение текстового поля показывается только в том случае, когда данное поле имеет фокус. Чтобы выделение текстового поля отображалось даже в тех случаях, когда текстовое поле не имеет фокуса, присвойте переменной alwaysShowSelection значение true. В приложении Flash Player 9 установить цвет выделения невозможно; поддержка настраиваемого цвета выделения может быть реализована в будущих версиях приложения Flash Player.

Руководство по actionscript. часть 5, стр. 138

Чтобы определить индекс первого выделенного символа в текстовом поле, используйте переменную экземпляра selectionBeginlndex класса TextField. Для определения индекса последнего выделенного символа в текстовом поле применяйте переменную экземпляра selectionEndlndex класса TextField. Чтобы определить позицию точки вставки (курсора), используйте переменную экземпляра caretlndex класса TextField. Чтобы программным путем выделить символы в текстовом поле или установить точку вставки, применяйте метод экземпляра setSelection ( ) класса TextField.

Стоит отметить, что в приложении Flash Player отсутствуют события, обозначающие изменение выделения текстового поля. Чтобы выявить изменения в выделении поля, периодически проверяйте значения переменных selectionBeginlndex и selectionEndlndex.

Чтобы заменить текущее выделение новым текстом, что может потребоваться в приложении с возможностью редактирования слов в стиле текстового процессора, используйте метод экземпляра replaceSelectedText ( ) класса TextField. Стоит отметить, однако, что метод replaceSelectedText ( ) работает только в тех случаях, когда текстовое поле имеет фокус или когда переменной always ShowSelec t ion присвоено значение true. Метод replaceSelectedText ( ) представляет собой удобную версию метода replaceText ( ), который был рассмотрен ранее в разд. «Изменение содержимого текстового поля». Метод replaceSelectedText ( ) работает точно так же, как и метод replaceText ( ), за исключением того, что он автоматически устанавливает значения параметров индексНачала и индексКонца в соответствии с текущим выделением.

Гипертекстовые ссылки

Чтобы добавить гипертекстовую ссылку в поле, мы используем переменную экземпляра url класса TextFormat или тег языка HTML. Обычно гипертекстовые ссылки используются для открытия конкретных ресурсов, находящихся

по указываемым URL-адресам. Например, следующий код создает текстовое поле, содержащее гипертекстовую ссылку, при активизации которой приложение Flash Player открывает сайт издательства O’Reilly в браузере, используемом в операционной системе по умолчанию.

var t:TextField = new TextField( );

t. htmlText = «To visit O’Reilly’s web site. «

+ «Click here«; t. autoSize = TextFieldAutoSize. LEFT;

Кроме того, гипертекстовые ссылки могут использоваться для выполнения кода на языке ActionScript. Подробную информацию можно найти в подразд. «Событие TextEvent. LINK» разд. «События текстового ввода» гл. 22.

Мы почти рассмотрели вопросы, касающиеся текстовых полей. Однако перед тем, как перейти к следующей главе, кратко познакомимся с представлением текстовых полей, создаваемых вручную в среде разработки Flash, в языке ActionScript.

Руководство по actionscript. часть 5, стр. 139

Текстовые поля и среда разработки Flash

В среде разработки Flash текстовые поля могут создаваться вручную с помощью инструмента Text (Текст). На этапе разработки каждое создаваемое вручную поле может иметь один из трех видов: статический, динамический или вводимый текст. На этапе выполнения каждое создаваемое вручную текстовое поле в коде на языке ActionScript представляется объектом, который соответствует типу поля, указываемому на этапе разработки.

Текстовые поля вида «статический текст» представляются экземплярами класса StaticText. Поля вида «динамический текст» представляются экземплярами класса TextField, переменной type которых присвоено значение TextFieldType. DYNAMIC. Текстовые поля вида «вводимый текст» представляются экземплярами класса TextField, переменной type которых присвоено значение TextFieldType. INPUT.

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

Чтобы получить доступ ко всему тексту во всех статических текстовых полях некоторого экземпляра класса DisplayObjectContainer, используйте класс TextSnapshot (основное назначение которого заключается в предоставлении возможности выделения текста в нескольких отдельных объектах StaticText).

Л %

Текстовые поля вида «статический текст» не могут создаваться с помощью кода на языке ActionScript; классы StaticText и TextSnapshot существуют исключительно для предоставления программного доступа к этим полям, создаваемым в среде разработки Flash.

Точно так же, как программисты на языке ActionScript могут устанавливать параметры отображения текста на этапе выполнения, авторы, использующие среду разработки Flash, могут использовать палитру Properties (Свойства) для выбора режима отображения текстовых полей на этапе компиляции. Параметры отображения, предоставляемые средой разработки Flash (и их эквиваленты в языке ActionScript), перечислены в табл. 27.10.

Таблица 27.10. Параметры отображения текста, предоставляемые средой разработки Flash

Значение на палитре Properties (Свойства) Описание Эквивалент в языке ActionScript

Use device fonts (Использовать шрифты устройства) Полагаемся на локальную среду воспроизведения для отображения текста с помощью шрифтов, установленных в системе конечного • пользователя Присвоить переменной embedFonts значение false

Bitmap text (no anti-alias) (Растровый текст (без сглаживания)) Когда выбран вид Bitmap text (Растровый текст), компилятор выравнивает фигуры по целым пикселам при вычислении контуров глифов (поэтому шрифт не выглядит сглаженным). На этапе выполнения эти контуры глифов отображаются с помощью встроенного визуализатора векторной графики приложения Flash Player, а не визуализатора FlashType Встроить шрифт, установив флажок Bitmap text (Растровый текст) в среде разработки Flash, а затем присвоить переменной embedFonts значение false. Недоступно, если компиляция выполняется с помощью приложения Flex Builder 2 или компилятора mxmlc

Anti-alias for animation (Сглаживание для анимации) Отображает текст с помощью стандартного визуализатора векторной графики приложения Flash Player Присвоить переменной antiAliasType значение AntiAliasType. NORMAL

Anti-alias for readability (Сглаживание для читабельности) Выводит текст с помощью визуализатора FlashType, используя параметры по умолчанию Присвоить переменной antiAliasType значение AntiAliasType. ADVANCED

Custom anti-alias (Настраиваемое сглаживание) Отображает текст с помощью визуализатора FlashType, используя настраиваемые параметры Присвоить переменной antiAliasType значение AntiAliasType. ADVANCED и определить настраиваемые параметры, используя методики, которые были рассмотрены ранее в разд. «Отображение текста с помощью встраиваемых шрифтов»

Загрузка… Пожалуйста, подождите…

Руководство по actionscript. часть 5, стр. 140

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

Руководство по actionscript. часть 6, стр. 001

ГЛАВА 28

Загрузка внешних отображаемых элементов

В ActionScript существует три способа добавления внешнего отображаемого элемента в приложение программным путем:

? использование класса flash. display. Loader для загрузки элемента на этапе выполнения;

? применение класса flash. net. Socket совместно с методом экземпляра loadBytes ( ) класса Loader для загрузки элемента на этапе выполнения через открытый сокет TCP/IP;

? использование тега метаданных [Embed] для встраивания элемента, находящегося в локальной файловой системе, на этапе компиляции.

Классы Loader и Socket являются собственными классами API среды выполнения Flash, в то время как для использования тега метаданных [Embed] требуется платформа разработки Flex. Все три подхода поддерживают следующие форматы отображаемых элементов:

? SWF (скомпилированные приложения Flash);

? JPEG, GIF или PNG (растровые изображения).

Кроме того, тег метаданных [Embed] поддерживает отображаемые элементы в формате SVG.

Продолжение:

1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,

41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,

77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,

109,110,111,112,113,114

Руководство по actionscript. часть 6, стр. 002

В этой главе будет рассказано, как использовать классы Loader и Socket, а также тег метаданных [ Embed ] для загрузки внешних отображаемых элементов. Подробную информацию о загрузке шрифтов вы сможете найти в гл. 27. Сведения о загрузке содержимого XML можно найти в гл. 18. Кроме того, информацию о загрузке других неотображаемых элементов, например переменных, бинарных данных или звуковых файлов, можно найти в описании классов URLLoader, URLStream и Sound в справочнике по языку ActionScript корпорации Adobe.

Класс Loader заменяет следующие инструменты языка ActionScript 2.0, предназначенные для загрузки элементов: класс MovieClipLoader; глобальные функции loadMovie() и loadMovieNum(); методы экземпляра loadMovie() и loadMovieNum() класса MovieClip.

Использование класса Loader для загрузки отображаемых элементов на этапе выполнения

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

1. Создать экземпляр класса flash, display. Loader.

2. Создать экземпляр класса flash. net. URLRequest, определяющий местоположение элемента.

3. Передать экземпляр класса URLRequest в метод load ( ) класса Loader.

В следующих разделах мы создадим пример класса Sunse tviewer, в котором подробно рассматриваются описанные шаги. Класс из нашего примера будет загружать единственное растровое изображение sunset. j pg. Освоив базовые положения загрузки элементов, вы узнаете, как отслеживать ход выполнения операции загрузки с помощью класса flash. display. Loaderlnf о. Наконец, мы рассмотрим код, необходимый для обращения к загруженному элементу и его добавления в список отображения.

Операции загрузки подчиняются ограничениям безопасности приложения Flash Player. м$ 4 * Полную информацию можно получить в гл. 19.

В классе SunsetViewer нашего примера мы предполагаем, что SWF-файл приложения SunsetViewer. swf будет размещен на сайте в той же директории, где находится загружаемое изображение sunset. j pg.

Руководство по actionscript. часть 6, стр. 003

Создание экземпляра класса Loader

Как мы уже знаем, первым шагом в загрузке любого отображаемого элемента на этапе выполнения с помощью класса Loader является создание экземпляра класса Loader. Этот экземпляр управляет операцией загрузки и предоставляет доступ к загруженному элементу. Мы создадим наш экземпляр класса Loader в методе-конструкторе класса SunsetViewer и присвоим его переменной экземпляра loader, как показано в листинге 28.1.

Листинг 28.1. Создание экземпляра класса Loader

Package { import flash. display.*;

public class SunsetViewer extends Sprite { private var loader:Loader;

public function SunsetViewer ( ) { loader = new Loader( ); // Создаем экземпляр класса Loader

Определение местоположения элемента

Чтобы загрузить внешний отображаемый элемент с помощью экземпляра класса Loader, мы должны указать местоположение этого элемента с помощью объекта flash. net. URLRequest. Каждый отдельный объект URLRequest описывает местоположение одного внешнего ресурса, находящегося либо в сети, либо в локальной файловой системе. Чтобы создать объект URLRequest, который определяет местоположение элемента, используйте следующий обобщенный код, присваивающий местоположение элемента переменной экземпляра url:

var urlRequest:URLRequest = new URLRequest( ); url Request, url = «ацреситЭпемента»:

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

var url:URLRequest = new URLRequesti» адреси[ИЭлемента»);

В обоих случаях aupecURLJneMeHTa — это строка, содержащая стандартный адрес URL. Например:

new URLRequest(«http://www. examp1e. com/image. jpg»);

Набор сетевых протоколов, которые допускается использовать в строке anpecURLdne-мента, зависит от операционной системы. Например, протоколы http: / /, https: / / и f tp: / / поддерживаются всеми операционными системами Windows, Macintosh и UNIX, однако обращение к содержимому справки Windows (ms-its:) может поддерживаться только в операционной системе Windows. Из соображений безопасности приложение Flash Player может также блокировать некоторые протоколы. Тем не менее в настоящее время корпорация Adobe не публикует список блокируемых протоколов. Более того, среда выполнения Flash не генерирует никаких сообщений об ошибках безопасности, относящихся конкретно к блокированию протокола. По этой причине при работе с редко используемыми протоколами не забывайте, что операции загрузки с применением таких протоколов могут потерпеть неудачу, не вызвав никаких ошибок.

Руководство по actionscript. часть 6, стр. 004

Помимо определения адреса URL, каждый объект URLRequest может также предоставлять дополнительную информацию для запрашиваемого по HTTP-протоколу ресурса. Чтобы указать заголовок HTTP-запроса, используемый метод, данные для метода POST, строку запроса и тип содержимого MIME, просто установите соответствующие переменные объекта URLRequest, как описано в справочнике по языку ActionScript корпорации Adobe. Например, чтобы определить заголовки HTTP-запроса, установите переменную экземпляра requestHeaders класса URLRequest.

Местоположение элемента может быть указано в виде абсолютного или относительного URL-адреса. Однако стоит отметить, что система приложения Flash Player, отвечающая за разрешение относительных адресов URL, зависит от способа запуска приложения Flash Player.

? Если приложение Flash Player запускается с целью отображения SWF-файла, встроенного в веб-страницу с помощью тега или, все от-

носительные адреса URL разрешаются относительно этой веб-страницы, а не относительно какого-либо SWF-файла. Более того, если веб-страница была открыта локально^ относительные адреса URL разрешаются локально. Если веб-страница была открыта с сайта, относительные адреса URL разрешаются с использованием адреса этого сайта. ? Когда приложение Flash Player запускается как автономное приложение или в результате непосредственного открытия SWF-файла в браузере, поддерживающем формат Flash, все относительные адреса URL разрешаются относительно первого SWF-файла, открытого в приложении Flash Player, — этот файл называется владельцем сцены. Более того, если владелец сцены был открыт локально, относительные адреса URL разрешаются локально; если владелец сцены был открыт с сайта, относительные адреса URL разрешаются с использованием адреса этого сайта.

*^ I Даже если первый SWF-файл, открытый в приложении Flash Player, будет удален со сцены, А щ он останется владельцем сцены и по-прежнему будет оказывать влияние на разрешение ц»У относительных URL-адресов.

Рассмотрим пример с использованием относительных адресов URL, который демонстрирует две описанные системы разрешения. Предположим, что мы встроили приложение SunsetViewer. swf в веб-страницу SunsetViewer. html и сохранили эти два файла в следующих отдельных директориях:

/vi ewer/SunsetVi ewer. html

/vi ewer/assets/SunsetVi ewer. swf

Предположим также, что из приложения SunsetViewer. swf мы хотим загрузить изображение sunset. jpg, которое тоже находится в директории /assets/:

/viewer/assets/sunset. jpg

Если мы считаем, что пользователь будет запускать приложение SunsetViewer. swf, открывая веб-страницу SunsetViewer. html, мы должны сформировать наш относительный URL-адрес относительно данной веб-страницы, как показано в следующей строке кода:

new URLRequest(«assets/sunset. jpg»);

Тем не менее, если мы считаем, что пользователь будет запускать приложение, непосредственно открывая файл SunsetViewer. swf, мы должны сформировать наш относительный URL-адрес относительно SWF-файла, а не веб-страницы, как показано в следующей строке кода:

new URLRequest(«sunset. jpg»);

*»,

^ I При распространении содержимого, воспроизводимого в приложении Flash Player, фор-

*S: А 9 мируйте все относительные адреса URL в соответствии с тем, как ваши пользователи

tlft будут запускать приложение Flash Player.



Полезные ссылки
Случайные записи
  • 27.10.2012">«Лаборатория Касперского»: Android 2.3.6 Gingerbread — любимая система злоумышленников
  • 23.01.2011">Руководство по actionscript. часть 1, стр. 027
  • 17.03.2011">Руководство по actionscript. часть 3, стр. 005
  • 22.03.2011">Руководство по actionscript. часть 2, стр. 007
  • 13.02.2014">Преимущества МДФ панелей
  • 23.02.2011">Руководство по actionscript. часть 7, стр. 033
  • 16.03.2011">Руководство по actionscript. часть 3, стр. 011
  • 03.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.54
  • 16.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.19
  • 08.03.2012">Новый рекорд Skype: 35 млн одновременных пользователей
  • 15.03.2011">Руководство по actionscript. часть 3, стр. 044
  • 08.03.2011">Руководство по actionscript. часть 4, стр. 078
  • 02.03.2011">Руководство по actionscript. часть 5, стр. 103
  • 02.03.2011">Руководство по actionscript. часть 5, стр. 097
  • 10.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.49
Опрос

Какие цвета вы предпочитаете?

View Results

Loading ... Loading ...