Библиотека Prototype – ваш путь в Web 2.0::Журнал СА 8.2007
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

Книжная полка  

От создания сайтов до разработки и реализации API

В издательстве «БХВ» недавно вышли книги, которые будут интересны системным администраторам, создателям

 Читать далее...

Разбор полетов  

Ошибок опыт трудный

Как часто мы легко повторяем, что не надо бояться совершать ошибки, мол,

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6195
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 6903
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4188
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 2989
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3795
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3805
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6299
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3152
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3446
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7263
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10628
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12352
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 13982
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9110
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7064
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5375
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4604
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3414
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3145
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3392
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3013
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Библиотека Prototype – ваш путь в Web 2.0

Архив номеров / 2007 / Выпуск №8 (57) / Библиотека Prototype – ваш путь в Web 2.0

Рубрика: Программирование /  Веб-программирование

Кирилл Сухов

Библиотека Prototype – ваш путь в Web 2.0

Часть 2: практика

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

В первой части статьи (см. №7 за 2007 г.) я провел краткий обзор основных функций библиотеки Prototype, к сожалению, недостаточно полный. Во второй части я уже собирался наверстать упущенное, но первые же читатели обратили внимание на тот факт, что в статье не было приведено ни одного внятного примера работы библиотеки. Так что сейчас мы будем рассматривать конкретную программу, созданную на её основе.

Для иллюстрации я выбрал Window Prototype – библиотеку, уже упомянутую в первой части. Конечно, можно было попробовать написать собственное приложение, но боюсь, что его объём значительно увеличит статью. В данном случае я могу не приводить полные варианты кода – читатель всегда может ознакомиться с первоисточником. Те функции Prototype, которые остались за рамками обзора, будут освещаться по мере развития событий.

Итак, наше приложение должно создавать окна, причём окна полноценные – со всеми элементами управления, с заданным контентом, которым может служить как произвольный URL, так и какое-либо сгенерированное сообщение. Кроме того, мы будем писать библиотеку, с понятным и расширяемым интерфейсом (какой и является Window Prototype).

Теперь начнём

Сначала главная HTML-страница нашего Prototype-приложения:

<html>

<head>

<title>Окошки</title>

<script type="text/javascript" src="/javascripts/prototype.js"> </script>

<script type="text/javascript" src="/javascripts/win.js"> </script>

<link href="/themes/default.css" rel="stylesheet" type="text/css">

<link href="/themes/alphacube.css" rel="stylesheet" type="text/css">

</head>

<body>

<script type="text/javascript">

function open_window(id){

win1 = new Window(id, {className: "alphacube", title: "Window1", width:200, height:150, top:200, left:100});

}

</script>

<center><a href="#" onclick="win1.show();">open window</a></center>

</body>

</html>

Сначала подключается JavaScript-файл с самой библиотеки Prototype (prototype.js), затем файл с нашим сценарием, который ещё предстоит написать. При клике по ссылке «open window» будет вызван сценарий, открывающий желаемое окно. Он создаёт объект Window со свойствами, заложенными в аргументах нового объекта. Первый из них это идентификатор создаваемого объекта, второй – записанный в формате JSON массив его свойств.

Подключаемые файлы каскадных таблиц стилей (default.css и spread.css) были взяты также из Window Prototype и имеют смысл только для наглядности, визуализации создаваемых объектов. Их код я здесь приводить не буду. Теперь осталась сущая ерунда – создать класс, на основе которого создаётся объект, и описать его поведение. Вперёд, препарируем библиотеку и создаём сценарий в файле win.js.

Начнём с создания нашего объекта:

var Window = Class.create();

Тут необходимы пояснения. Объект Class используется для объявления пользовательских классов библиотеки. По аналогии с Java он имеет метод initailize(), используемый как конструктор, cамо объявление класса осуществляется методом create(), также знакомым по высокоуровневым ООП языкам программирования.

Теперь определим реализацию класса:

Window.prototype = {initialize: function() {

    var optionIndex = 0;

    if (arguments.length > 0) {

      if (typeof arguments[0] == "string" ) {

        id = arguments[0];

        optionIndex = 1;

      }

      else

        id = arguments[0] ? arguments[0].id : null;

    }

...............

Тут, мне кажется, всё должно быть понятно – мы просто оставляем возможность опустить первый аргумент (идентификатор). Это понадобится для того, чтобы создавать произвольное количество объектов. Впрочем, без id всё равно не обойтись, и он будет сгенерирован:

if (!id)

 id = "window_" + new Date().getTime();

Далее перечисляем желаемые свойства объекта:

this.options = Object.extend({

className:         "dialog",

blurClassName:     null,

minWidth:          100,

minHeight:         20,

resizable:         true,

closable:          true,

minimizable:       true,

maximizable:       true,

draggable:         true,

userData:          null,

showEffect:        (Window.hasEffectLib ? Effect.Appear : Element.show),

hideEffect:        (Window.hasEffectLib ? Effect.Fade : Element.hide),

showEffectOptions: {},

      hideEffectOptions: {},

      effectOptions:     null,

      parent:            document.body,

      title:             "&nbsp;",

      url:               null,

      onload:            Prototype.emptyFunction,

      width:             200,

      height:            300,

      opacity:           1,

      recenterAuto:      true,

      wiredDrag:         false,

      closeCallback:     null,

      destroyOnClose:    false,

      gridX:             1,

      gridY:             1     

    }, arguments[optionIndex] || {});

Мы сразу задали все свойства окна, некоторые из них в нашей конкретной задаче точно не понадобятся, но давайте не забывать, мы пишем не приложение, а библиотеку. Надо заметить, что JavaScript, довольно демократичный язык, допускающий многие «вольности». В числе таковых неопределённое количество аргументов функции. Использовав объект options, мы создали массив свойств нашего окна, которые используются, если явно не указаны при его иницмализации.

Далее задаём область, в которой будет создаваться окно (по умолчанию это document.body):

    if (this.options.parent != document.body) 

     this.options.parent = $(this.options.parent);

Теперь создаём окно:

    this.element = this._createWindow(id);      

     this.element.win = this;

Далее в конструкторе стоит задать некоторые методы, но это отложим, пока установим только размеры и заголовок:

    if (this.width && this.height)

     this.setSize(this.options.width, this.options.height);

     this.setTitle(this.options.title)

На этом конструктор пока закончим:

    Windows.register(this);      

 },

Смысл последней строчки будет ясен позже, объект Windows мы ещё опишем.

Теперь очередь метода _createWindow(). Тут всё довольно просто. Создаётся объект, представляющий собой HTML-код (три таблицы), каждому элементу которого присвоено стандартное имя класса (производное от базового):

    _createWindow: function(id) {

    var className = this.options.className;

    var win = document.createElement("div");

    win.setAttribute('id', id);

    win.className = "dialog";

    var content;

    if (this.options.url)

      content= "<iframe frameborder=\"0\" name=\"" + id + "_content\"  id=\"" + id + "_content\" src=\"" + this.options.url + "\"> </iframe>";

    else

      content ="<div id=\"" + id + "_content\" class=\"" +className + "_content\"> </div>";

    var closeDiv = this.options.closable ? "<div class='"+ className +"_close' id='"+ id +"_close' onclick='Windows.close(\""+ id +"\", event)'> </div>" : "";

    var minDiv = this.options.minimizable ? "<div class='"+ className + "_minimize' id='"+ id +"_minimize' onclick='Windows.minimize(\""+ id +"\", event)'> </div>" : "";

    var maxDiv = this.options.maximizable ? "<div class='"+ className + "_maximize' id='"+ id +"_maximize' onclick='Windows.maximize(\""+ id +"\", event)'> </div>" : "";

    var seAttributes = this.options.resizable ? "class='" + className + "_sizer' id='" + id + "_sizer'" : "class='"  + className + "_se'";

    var blank = "../themes/default/blank.gif";

    win.innerHTML = closeDiv + minDiv + maxDiv + "\

      <table id='"+ id +"_row1' class=\"top table_window\">\

        <tr>\

          <td class='"+ className +"_nw'></td>\

          <td class='"+ className +"_n'><div id='"+ id +"_top' class='"+ className +"_title title_window'>"+ this.options.title +"</div></td>\

          <td class='"+ className +"_ne'></td>\

        </tr>\

      </table>\

      <table id='"+ id +"_row2' class=\"mid table_window\">\

        <tr>\

          <td class='"+ className +"_w'></td>\

            <td id='"+ id +"_table_content' class='"+ className +"_content' valign='top'>" + content + "</td>\

          <td class='"+ className +"_e'></td>\

        </tr>\

      </table>\

        <table id='"+ id +"_row3' class=\"bot table_window\">\

        <tr>\

          <td class='"+ className +"_sw'></td>\

            <td class='"+ className +"_s'><div id='"+ id +"_bottom' class='status_bar'><span style='float:left; width:1px; height:1px'></span></div></td>\

            <td " + seAttributes + "></td>\

        </tr>\

      </table>\

    ";

    Event.observe($(id + "_content"), "load", this.options.onload);

    return win;

  },

Структура окна, конечно, может быть другой, но я хочу обратить внимание на ключевые моменты:

  • все элементы окна помещены в один (родительский) элемент div, снабженный уникальным идентификатором;
  • ко всем элементам управления (стандартные «свернуть», «развернуть», «закрыть», «перетащить») добавлены обработчики событий (да, да их ещё предстоит создать);
  • окно может отображать, как заданный URL, так и сгенерированный контент.

Результат мы можем уже наблюдать (см. рис. 1), но он пока не очень впечатляет. В самом деле, зачем было писать столько строк кода, когда то же самое можно получить простейшими DHTML-приёмами? На самом деле все нормально. Кода придется написать ещё втрое больше, но в прототипе мы сразу же заложили возможности для любых манипуляций с объектом-окном. Правда, окно мы не собираемся создавать в одном экземпляре (а какой смысл?). Для работы с множеством окон мы создадим ещё один объект, который разработчики Windows Prototipe назвали не слишком оригинально.

Рисунок 1. Окошко появилось

Рисунок 1. Окошко появилось

Итак, объект Windows:

  var Windows = {

  windows: [],

  observers: [],

  focusedWindow: null,

  maxZIndex: 0,

  overlayShowEffectOptions: {duration: 0.5},

  overlayHideEffectOptions: {duration: 0.5},

  addObserver: function(observer) {

    this.removeObserver(observer);

    this.observers.push(observer);

  },

  removeObserver: function(observer) { 

    this.observers = this.observers.reject( function(o) { return o==observer });

  },

  ...

}

Задача данного объекта хранить сведения о коллекции объектов Window и переадресовывать события к обработчику для заданного окна. Как вполне ясно из кода, в массиве windows сохраняются все созданные объекты-окошки, в массиве observers – заданные обработчики.

Методы addObserver и removeObserver оперируют с обработчиками событий, добавляя или убирая их у объектов.

Сюда же добавляем два необходимых для манипуляций с объектами метода:

notify: function(eventName, win) { 

    this.observers.each( function(o) {if(o[eventName]) o[eventName](eventName, win);});

  },

getWindow: function(id) {

    return this.windows.detect(function(d) { return d.getId() ==id });

  },notify: function(eventName, win) { 

    this.observers.each( function(o) {if(o[eventName]) o[eventName](eventName, win);});

  },

  getWindow: function(id) {

    return this.windows.detect(function(d) { return d.getId() ==id });

  },

Последний метод, как вы помните, вызывается конструктором при создании окна, реализация getId() и других вспомогательных манипуляций в данном случае принципиально не важна.

Осталось задать поведение создаваемых объектов, прописав все необходимые методы в объекте Windows и их реализацию в объекте Window. Естественно, мы это не будем делать в полном объёме (тем более что разработчики Windows Prototipe давно обо всём позаботились), но кое-что попробуем.

Оживляем объект

Прежде всего нужно связать составляющие созданного объекта с событиями (наведением мыши, перетаскиванием, кликами). Опять-таки это будет несколько сложнее, чем в традиционном DHTML, но зато и возможностей будет больше. Сначала добавим в конструктор следующие строки:

this.eventMouseDown = this._initDrag.bindAsEventListener(this);

this.eventMouseUp = this._endDrag.bindAsEventListener(this);

this.eventMouseMove = this._updateDrag.bindAsEventListener(this);

this.eventOnLoad = this._getWindowBorderSize.bindAsEventListener(this);

this.eventMouseDownContent = this.toFront.bindAsEventListener(this);

this.eventResize = this._recenter.bindAsEventListener(this);

this.topbar = $(this.element.id + "_top");

this.bottombar = $(this.element.id + "_bottom");

this.content = $(this.element.id + "_content");

Event.observe(this.topbar, "mousedown", this.eventMouseDown);

Event.observe(this.bottombar, "mousedown", this.eventMouseDown);

Event.observe(this.content, "mousedown", this.eventMouseDownContent);

Event.observe(window, "load", this.eventOnLoad);

Event.observe(window, "resize", this.eventResize);

Event.observe(window, "scroll", this.eventResize);

Event.observe(this.options.parent, "scroll", this.eventResize);

Всё, теперь можно описывать поведение объектов. Для примера возьмём «сворачивание» окна при нажатии мышкой на соответствующую кнопку.

Для достижения этого эффекта сначала пропишем соответствующий метод объекта Windows:

minimize: function(id, event) {

    var win = this.getWindow(id)

    if (win && win.visible)

      win.minimize();

    Event.stop(event);

  },

Затем его реализацию в объекте Window:

minimize: function() {

    if (this.resizing)

      return;

    var r2 = $(this.getId() + "_row2");

    if (!this.minimized) {

      this.minimized = true;

      var dh = r2.getDimensions().height;

      this.r2Height = dh;

      var h  = this.element.getHeight() - dh;

 

      if (! this.useTop) {

        var bottom = parseFloat(this.element.getStyle('bottom'));

        this.element.setStyle({bottom: (bottom + dh) + 'px'});

      }

    }

    else {      

      this.minimized = false;

      var dh = this.r2Height;

      this.r2Height = null;

      if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {

        new Effect.ResizeWindow(this, null, null, null, this.height + dh, {duration: Window.resizeEffectDuration});

      }

      else {

        var h  = this.element.getHeight() + dh;

        this.height += dh;

        this.element.setStyle({height: h + "px"})

        r2.show();

      }

      if (! this.useTop) {

        var bottom = parseFloat(this.element.getStyle('bottom'));

        this.element.setStyle({bottom: (bottom - dh) + 'px'});

      }

      this.toFront();

    }

  },

Я понимаю, что выглядит всё не очень прозрачно, но тем не менее описывать методы вроде show(), getHeight() или toFront() не буду (их реализацию читатель всегда может посмотреть в исходниках). Объект Effect и метод ResizeWindow являются специфичными для Windows prototype, я бы с удовольствием разобрал их работу, но объём статьи при этом возрастёт в несколько раз. Чтобы воспользоваться нашим объектом, нужно только всего ничего – прописать все остальные методы, задающие его поведение.

Работаем с библиотекой

Теперь представим, что мы прописали все методы и свойства и можем пожинать плоды нудной работы (пусть и не нашей, но всё же). Сначала чуть модифицируем вызов нашего окошка:

function open_window(id){

win1 = new Window(id, {className: "alphacube", title: "Window1", width:200, height:150, top:200, left:100});

win1.getContent().innerHTML = "<h1>Preved</h1>";

win1.show();

}

Теперь окно живёт – его можно свернуть, развернуть на весь экран, перетащить, наконец, закрыть. Все свойства окна можно установить посредством вызова методов, что и делаем, наполняя окно чрезвычайно полезным контентом (см. рис. 2).

Рисунок 2. Hellow Word

Рисунок 2. Hellow Word

Теперь создадим окно на основе другого класса (см. рис. 3):

function next_window(){

win2 = new Window( {className: "spread", title: "Window2",opacity:0.5, width:200, height:150, top:200, left:100});

win2.getContent().innerHTML = "<h1>Preved</h1>";

win2.show();

}

Рисунок 3. Меняем стиль, прозрачность

Рисунок 3. Меняем стиль, прозрачность

Поскольку мы не задали жёстко идентификатор объекта, создать таких окон можно сколько угодно и сколько угодно издеваться над ними (см. рис. 4, 5).

Рисунок 4. Размножаемся

Рисунок 4. Размножаемся

Рисунок 5. Трансформация окон

Рисунок 5. Трансформация окон

В конце концов создадим самое правильное окно:

win2 = new Window( {className: "spread", title: "samag",opacity:0.5, width:200, height:150, top:200, left:100, url=”http://samag.ru”});

Результат представлен на рис. 6.

Рисунок 6. Загрузка правильного URL

Рисунок 6. Загрузка правильного URL

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

Несмотря на то, что библиотека Prototype создана и активно используется довольно давно, до самого последнего времени она не имела ни официальной документации, ни даже полноценной домашней страницы. К счастью, сейчас эти проблемы решены – на сайте библиотеки http://www.prototypejs.org/api доступно описание классов и методов.

Джонатан Снук (Jonathan Snook, http://www.snook.ca) проделал колоссальную работу, собрав элементы библиотеки в единую диаграмму, отражающую связь и иерархию объектов Prototype. Рекомендую использовать её для изучения структуры библиотеки (см. рис. 7).

Рисунок 7. Связь и иерархия объектов библиотеки Prototype

Рисунок 7. Связь и иерархия объектов библиотеки Prototype

Приложения на JavaScript?

В первой части этого опуса я упомянул о нескольких библиотеках, созданных на основе prototype. Они впечатляют своими возможностями, но всё же это библиотеки – инструменты разработчика, до которых нет дела конечному пользователю.

В качестве иллюстрации готового JavaScript-приложения я собирался привести несколько примеров, но в процессе подготовки наткнулся на один, самый эффектный на настоящее время, которым решил и ограничиться. Знакомьтесь – Cumulate Draw (см. рис. 8).

Рисунок 8. Работа сервиса Cumulate Draw

Рисунок 8. Работа сервиса Cumulate Draw

Честно говоря, будь я разработчиком этого сервиса, я непременно брал бы деньги за его использование. Это вполне достойная замена среды MSVisio прямо в окне браузера. Конечно, сказать, что данное приложение целиком сделано на основе Prototype, нельзя, скорее всего, оно создано с использованием этой библиотеки. Тем не менее серверная часть составляет в ней явно не так много, основная задача по реализации функционала приходится на интерфейс, в чём можно убедиться, посмотрев исходники на JavaScript, которые вполне доступны для изучения.

Я думаю, наличие таких приложений не оставляет сомнения в возможностях и библиотеки Pritotype.

  1. Библиотека Window Prototype – http://prototype-window.xilinus.com/index.html.
  2. Сервис Cumulate Draw – http://www.cumulatelabs.com/draw/draw.html?release=0.4.7.

Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru