corner imagecorner image
FeaturesPluginsDocs & SupportCommunityPartners

Создание комнаты для беседы на Ajax с элементом Dynamic Faces "Ajax Transaction"


В этом руководстве описывается создание веб-приложения "Комната для беседы" на Ajax с элементами, которые сами не поддерживают Ajax, также известными как элементы POJC (Plain Old JavaServer Faces Components – простые старые элементы JavaServer Faces). Это достигается с помощью технологии Dynamic Faces, являющейся расширением технологии JavaServer Faces, которая позволяет легко реализовать функциональные возможности Ajax. В частности, используется элемент "Ajax Transaction", поставляемый с библиотекой элементов управления Dynamic Faces (0.2) и позволяющий визуально настраивать функциональные возможности Ajax на этапе проектирования. Приложение "Комната для беседы" включает в себя одну визуализованную страницу, показанную ниже, и полностью основано на технологии Ajax. Стандартные способы передачи данных между страницами не применяются. Это означает, что запрос Ajax передается при отправке пользователем комментария, когда он вводит текст в текстовом поле и нажимает кнопку "Send" или клавишу Enter. Запросы Ajax также используются страницей для непрерывного опроса сервера в целях обновления текста комментариев.


Содержание

Содержимое на этой странице относится к среде IDE NetBeans 6.0

Для работы с этим руководством требуется программное обеспечение и ресурсы, перечисленные ниже.

Программное обеспечение или ресурс Требуемая версия
Среда IDE NetBeans Web & Java EE, версия 6.1 или 6.0
Комплект для разработчика на языке Java (JDK) версия 6 или
версия 5
Элементы JavaServer Faces
Платформа Java EE
1.1 с J2EE 1.4
Сервер приложений GlassFish V2
База данных TRAVEL Не требуется

Требования для работы с руководством

Перед началом работы необходимо установить на компьютере следующее программное обеспечение:

  • Среда IDE NetBeans 6.0 или 6.1 с функциональными возможностями Web и Java EE (входят в состав варианта загрузки "Web and Java EE" и "All") (загрузить)
  • Подключаемый модуль "Visual Web Samples". Этот подключаемый модуль содержит библиотеку элементов управления Dynamic Faces (0.2). Следуйте указаниям в разделе "Установка подключаемого модуля" в руководстве Установка подключаемого модуля "Visual Web Samples". Убедитесь в том, что выбраны значения для "Visual Web JSF Post Release Samples" и для "Visual Web JSF Backwards Compatibility Kit".

Веб-приложение "Комната для беседы" на Ajax

Создание проекта

  1. Выберите в главном меню "File > New Project".
  2. В мастере создания проекта выберите "Web" в списке "Categories" и "Web Application" в списке "Projects", а затем нажмите кнопку "Next".
  3. Присвойте проекту имя "AjaxChatRoom" и выберите местоположение проекта.
  4. Выберите "Sun Java System Application Server" в поле "Server" и "J2EE 1.4" в поле "Java EE Version" и проверьте, что установлены флажки "Set Source Level to 1.4" и "Set as Main Project". Затем нажмите кнопку "Next".

    Мастер создания веб-приложения
  5. Выберите "Visual Web JavaServer Faces" и нажмите кнопку "Finish".

Настройка дескриптора развертывания

Для работы с технологией Dynamic Faces требуется параметр инициализации в дескрипторе развертывания веб-приложения.

  1. Разверните узел "Web Pages > WEB-INF" в окне "Projects".
  2. Дважды щелкните файл web.xml для его открытия в редакторе.
  3. На панели инструментов редактора щелкните "Servlets" и затем нажмите кнопку "Add", которая появляется под строкой "Initialization Parameters", как показано на следующем рисунке.

    Параметры инициализации сервлета web.xml
  4. В диалоговом окне "Add Initialization Parameter" введите javax.faces.LIFECYCLE_ID в текстовое поле "Param Name", введите com.sun.faces.lifecycle.PARTIAL в текстовое поле "Param Value" и нажмите кнопку "OK".

    Диалоговое окно "Add Initialization Parameter"
    В редакторе появится новый параметр.
  5. На панели инструментов изменения щелкните "XML" и найдите lifecycle для отображения изменений в необработанном XML.
  6. Нажмите комбинацию клавиш Ctrl-S для сохранения изменений в файле web.xml и закройте вкладку для закрытия файла.

Добавление к проекту библиотеки элементов управления Dynamic Faces

  1. В окне "Projects" щелкните правой кнопкой мыши узел "Component Libraries" и выберите "Add Component Library", как показано ниже.

    Добавление библиотеки элементов
  2. В диалоговом окне "Add Components Library" выберите "Dynamic Faces Components (0.2)" и щелкните "Add Component Library" для закрытия диалогового окна.

    В окне "Palette" появится новый раздел "Dynamic Faces".

Добавление кода к компоненту приложения

  1. В окне "Projects" разверните узел "Source Packages > ajaxchatroom" и дважды щелкните файл ApplicationBean1.java для его открытия в редакторе исходного кода.
  2. Выполните прокрутку до нижней части файла ApplicationBean1.java и добавьте следующий код перед последней закрывающей фигурной скобкой.


    Пример кода 1: код компонента приложения для сохранения комментариев и создания анонимных имен пользователя
        private int nextAnonIndex;
        private final int MAX_ENTRIES = 100;
        //список массивов строк, каждый массив длиной 2
        private List entryList = new LinkedList();
        //массив с содержанием, аналогичным entryList
        private String[][] entries;
        public String[][] getEntries() {
            synchronized(this.entryList) {
                return this.entries;
            }
        }
        public void addEntry(String username, String comment) {
            if (comment == null || comment.length() < 1) {
                return;
            }
            if (username == null) {
                username = "anonymous";
            }
            synchronized(this.entryList) {
                if (this.entryList.size() == MAX_ENTRIES) {
                    this.entryList.remove(0);
                }
                String[] entry = new String[]{username, comment};
                this.entryList.add(entry);
                this.entries =
                  (String[][])this.entryList.toArray(
                  new String[this.entryList.size()][entry.length]);
            }
        }
        public synchronized String getNextAnonUsername() {
            nextAnonIndex++;
            return "anonymous" + nextAnonIndex;
        }

    В этом коде каждый комментарий и соответствующее имя пользователя сохраняются как запись текста, т.е. String[] объект длины 2. Значения сохраняются в переменных entryList и entries. При добавлении комментария с помощью метода addEntry или при получении копий записей с помощью метода getEntries код клиента должен получить монитор (т.е. синхронизировать) по this.entryList, что влияет на производительность, но позволяет сохранить целостность данных. В тексте поддерживается максимальное количество записей, как определено в MAX_ENTRIES.

    Доступ к приложению для пользователей будет возможен через URL-адрес в формате http://server-ip-address:8080/AjaxChatRoom?username=someuser. Появится указанное имя пользователя наряду с любыми комментариями, переданными пользователем. Если пользователь получает доступ к приложению через URL-адрес, не содержащий имя пользователя, наряду с комментариями пользователя появится анонимное имя пользователя. В таком случае при вызове метода getNextAnonUsername будет создано анонимное имя пользователя, которое является уникальным в рамках приложения.
  3. Щелкните правой кнопкой мыши в исходном коде и выберите "Fix Imports".

    Поскольку для класса "List" имеется несколько вариантов выбора, появляется диалоговое окно "Fix Imports".

    Диалоговое окно "Fix Imports"
  4. Для подтверждения списка java.util в качестве полного имени для списка нажмите кнопку "OK".
  5. Закройте и сохраните файл.

Добавление кода для хранения имени пользователя

  1. В окне "Projects" дважды щелкните "Source Packages > ajaxchatroom > SessionBean1.java" для открытия этого файла в редакторе исходного кода.
  2. Выполните прокрутку до нижней части файла SessionBean1.java и добавьте следующий код перед последней закрывающей фигурной скобкой.

    Пример кода 2: код сеансного компонента для сохранения имени пользователя
        private String username;
        public synchronized String getUsername() {
            return username;
        }
        public synchronized void setUsername(String username) {
            this.username = username;
        }

    Как будет показано в примере кода 5, при передаче пользователем комментария метод действия извлекает из контекста сеанса имя пользователя для его записи наряду с комментарием. Поскольку несколько потоков выполнения, связанных с одним сеансом, могут получать доступ к методам получения и установки, выполняется синхронизация методов.
  3. Закройте и сохраните файл.
  4. В окне "Projects" дважды щелкните "Source Packages > ajaxchatroom > Page1.java" и затем откройте исходный код Java для страницы.
  5. В окне "Navigator" дважды щелкните prerender() для перехода к этому методу в редакторе исходного кода.

    Переход к методу "prerender"
  6. Добавьте следующий код, выделенный полужирным шрифтом, в метод prerender:

    Пример кода 3: код страницы Page1 для сохранения имени пользователя
        public void prerender() {
            String username = (String)getExternalContext().getRequestParameterMap().get("username");
            if (username != null) {
                getSessionBean1().setUsername(username);
            }
            else if (getSessionBean1().getUsername() == null) {
                getSessionBean1().setUsername(getApplicationBean1().getNextAnonUsername());
            }
        }

    Если в течение текущего запроса страница открывается первый раз и в URL-адресе было указано имя пользователя, отображение параметров запроса будет содержать это имя пользователя. В таком случае необходимо сохранить имя пользователя в сеансном компоненте. Если отображение параметров запроса не содержит имя пользователя, возможны два варианта: либо страница была открыта в первый раз и в URL-адресе не было указано имя пользователя, либо текущий запрос является запросом Ajax. В предыдущем случае, если имя пользователя не было предварительно сохранено в сеансном компоненте, необходимо создать и сохранить анонимное имя пользователя. В случае запроса Ajax имя пользователя уже было сохранено в сеансном компоненте при первоначальном открытии страницы.

Добавление свойства "transcript" к файлу "Page1.java"

  1. Выполните прокрутку до конца файла Page1.java и добавьте следующий код перед последней закрывающей фигурной скобкой.

    Пример кода 4: код свойства transcript
        public String getTranscript() {
            String[][] entries =
                getApplicationBean1().getEntries();
            if (entries == null) {
                return null;
            }
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < entries.length; i++) {
                String entryUsername = entries[i][0];
                String comment = entries[i][1];
                String color = "purple";
                String username = getSessionBean1().getUsername();
                if (username.equals(entryUsername)) {
                    color = "blue";
                }
                sb.append(
                    "<div><span style=\"font-weight:bold;color:");
                sb.append(color);
                sb.append("\">[");
                sb.append(entryUsername);
                sb.append("]</span> ");
                sb.append(comment);
                sb.append("</div>");
            }
            return sb.toString();
        }


    Этот метод предоставляет содержимое текста в качестве объекта String, при этом имя пользователя выделяется в записи синим цветом при его совпадении с именем пользователя, сохраненным в "SessionBean1", и фиолетовым в противном случае. В результате собственные записи пользователя выделяются на экране синим цветом, а записи других участников беседы – фиолетовым цветом.
  2. (Дополнительно) Щелкните правой кнопкой мыши и выберите "Format Code", затем для сохранения изменений нажмите кнопку "Save All" на основной панели инструментов.

Создание интерфейса пользователя

  1. Вернитесь к Visual Designer для страницы "Page1".
  2. Перетащите элемент "Layout Panel" из раздела палитры "Layout".
  3. В Visual Designer выберите элемент "Layout Panel" и сдвигайте правый нижний указатель размера вниз и вправо до тех пор, пока элемент не достигнет размера приблизительно 14 квадратов шириной и 10 квадратов высотой.

    Изменение элемента "Layout Panel"
  4. В окне "Properties" измените значение свойства элемента "Layout Panel"id на transcriptPanel.
  5. Нажмите кнопку с многоточием (...) для свойства style, добавьте следующие правила к стилю CSS и нажмите кнопку "OK".

    ; overflow: auto; border: 2px solid black;

    Установка для свойства стиля overflow значения auto при необходимости вызывает отображение полосы прокрутки в тексте беседы. Обратите внимание, что свойство элемента "transcriptPanel Layout Panel" panelLayout теперь имеет значение flow, которое является значением по умолчанию. В действиях 6–10, приведенных ниже, рассматривается добавление элемента "Static Text" в качестве нижестоящего элемента "transcriptPanel Layout Panel" и привязка свойства элемента "Static Text" text к свойству transcript страницы "Page1".
  6. Перетащите элемент "Static Text" из раздела "Basic" окна "Palette" в "transcriptPanel Layout Panel". Перед тем, как отпускать кнопку мыши, убедитесь, что контур "transcriptPanel" выделен синим цветом; в этом случае элемент "transcriptPanel" содержит элемент "Static Text".
  7. В окне "Properties" измените свойство элемента "Static Text" id на transcriptText и удалите флажок escape для установки для этого свойства значения false.

    Изменение значения свойства escape на false приводит к тому, что обозревателем анализируются любые теги разметки, встроенные в текст. Это обеспечивает появление записей текста с необходимым форматированием, например, выделением текста синим или фиолетовым цветом.
  8. В Visual Designer щелкните правой кнопкой мыши элемент "transcriptText Static Text" и выберите "Bind to Data".
  9. В диалоговом окне "Bind to Data" щелкните вкладку "Bind to an Object".
  10. Выберите "Page1 > transcript" и нажмите кнопку "OK".

    Привязка элемента "transcriptText" к #{Page1.transcript}
  11. Перетащите элемент "Text Field" из раздела "Basic" окна "Palette" и поместите его под элементом "transcriptPanel".
  12. В окне "Properties" измените свойство элемента "Text Field" id на comment.
  13. Измените комментарий свойства элемента "Text Field" columns на 60.
  14. Перетащите элемент "Button" из раздела "Basic" окна "Palette" в правую часть комментария "Text Field", введите Send и нажмите клавишу Enter.
  15. Нажмите кнопку с многоточием (...) для свойства style, добавьте следующие правила к стилю CSS и нажмите кнопку "OK".

    ; width: 70px
  16. В окне "Properties" измените значение свойства элемента "Button" id на send.

    Страница "Page1" должна выглядеть следующим образом.

    Интерфейс пользователя для комнаты для беседы в Visual Designer
  17. В Visual Designer дважды щелкните элемент "send Button".

    В среде IDE создается метод действия для кнопки "Send", который отображается в редакторе исходного кода.
  18. Добавьте к методу следующий код, выделенный полужирным шрифтом.

    Пример кода 5: обработчик действия кнопки
        public String send_action() {
          String comment = (String)getComment().getText();
          String username = getSessionBean1().getUsername();
          getApplicationBean1().addEntry(username, comment);
          return null;
        }

    Этот код извлекает любой текст, введенный пользователем в комментарий "Text Field", и передает этот текст в метод "addEntry", при этом комментарий пользователя добавляется к тексту беседы.

Настройка транзакций Ajax для передачи комментариев и опроса

Элемент "Ajax Transaction", поставляемый с библиотекой элементов управления Dynamic Faces (0.2), позволяет на этапе проектирования визуально настраивать функциональные возможности Ajax путем вывода на экран в Visual Designer различных элементов с цветными окантовками. Обязательным является указание элементов, передающих на сервер данные при запуске транзакции Ajax, а также элементов, выполняющих повторную визуализацию при получении клиентом ответа Ajax. Элементы, передающие на сервер данные, отображаются в Visual Designer со сплошной окантовкой, а элементы, выполняющие повторную визуализацию, отображаются с пунктирной окантовкой. Кроме того, для запуска транзакции Ajax необходимо вставить строку кода JavaScript.

В этом разделе описана настройка двух типов транзакций Ajax: для передачи комментариев и для опроса сервера. Запуск транзакции Ajax commentTx происходит при нажатии пользователем кнопки "Send" или клавиши Enter. При запуске commentTx комментарий "Text Field" и кнопка "Send" передают данные на сервер посредством запроса Ajax. При получении клиентом ответа Ajax элемент "transcriptText StaticText" выполняет повторную визуализацию. Первоначальный запуск транзакции Ajax pollTx происходит при загрузке страницы. Впоследствии при получении клиентом ответа Ajax, соответствующего транзакции Ajax pollTx, происходит повторный запуск pollTx после небольшой паузы. Таким образом реализуется непрерывный опрос сервера. При запуске pollTx не выполняется передача данных каких-либо элементов посредством запроса Ajax (поскольку происходит только получение, а не изменение данных текста), а при получении клиентом ответа Ajax элементом "transcriptText StaticText" выполняется повторная визуализация. В результате в обозревателе происходит непрерывное обновление текста комментариев.

  1. Вернитесь к Visual Designer для страницы "Page1".
  2. На панели инструментов Visual Designer нажмите кнопку "Show Virtual Forms" Кнопка "Show Virtual Forms".

    Элемент "Ajax Transaction" обеспечивает подобие функциональных возможностей Ajax функциональности виртуальных форм для стандартных способов передачи. При нажатии кнопки "Show Virtual Forms" отображаются как виртуальные формы, так и транзакции Ajax, настроенные для страницы.

  3. Разверните раздел "Dynamic Faces" в окне "Palette" и перетащите элемент "Ajax Transaction" из раздела "Dynamic Faces" в Visual Designer.

    В нижней части Visual Designer появляется поле "Ajax Transaction Legend" и транзакция Ajax "ajaxTransaction1", выделенная синим цветом.

    Окно "Ajax Transaction Legend"
  4. В Visual Designer выберите элемент "Text Field" для комментария и нажмите кнопку "Send". Затем щелкните правой кнопкой мыши и выберите "Configure Ajax Transactions".

    Появится диалоговое окно "Configure Ajax Transactions". В верхней части диалогового окна появятся строки send и comment, указывающие, что проводится настройка транзакций Ajax для кнопки "Send" и элемента "Text Field" комментария.
  5. В диалоговом окне "Configure Ajax Transactions" дважды щелкните внутри поля "Name", введите commentTx для переименования транзакции Ajax и нажмите клавишу Enter.
  6. Установите значение "Yes" в поле "Send Input" и нажмите кнопку "OK" для закрытия диалогового окна.

    Настройка транзакций Ajax для элементов отправки и добавления комментариев

    Элемент "Text Field" комментария и кнопка "Send" отображаются в Visual Designer со сплошной синей окантовкой, указывающей на то, что данные этих элементов были переданы на сервер посредством запроса Ajax при запуске транзакции Ajax "commentTx". Кнопка "Send" должна передавать на сервер свои входные данные, что информирует сервер о нажатии кнопки. В разделе Adding JavaScript, приведенном ниже, описано добавление строки кода JavaScript, с помощью которой происходит запуск транзакции Ajax "commentTx" при нажатии пользователем кнопки "Send" или клавиши Enter.

    Visual Designer после настройки транзакций Ajax для элементов передачи и добавления комментариев
  7. Выберите в проектировщике элемент "transcriptText StaticText". Щелкните правой кнопкой мыши и выберите "Configure Ajax Transactions".

    Появится диалоговое окно "Configure Ajax Transactions". В верхней части диалогового окна появится строка transcriptText, указывающая на то, что выполняется настройка транзакций Ajax для элемента "transcriptText StaticText".
  8. В диалоговом окне "Configure Ajax Transactions" щелкните "New" для настройки новой транзакции Ajax.
  9. Выберите красный как цвет, соответствующий новой транзакции Ajax.
  10. Дважды щелкните в поле "Name" новой транзакции Ajax, введите pollTx и нажмите клавишу Enter.
  11. Выберите в поле "Re-Render" транзакций Ajax commentTx и pollTx значение "Yes" и нажмите кнопку "OK" для закрытия диалогового окна.

    Настройка транзакций Ajax для элемента "transcriptText"

    Элемент "transcriptText Static Text" отображается с синей и красной пунктирной окантовкой, указывающей на то, что повторная визуализация происходит всякий раз при получении клиентом ответа Ajax, соответствующего транзакциям Ajax commentTx или pollTx. В разделе Добавление JavaScript, приведенном ниже, описано добавление логики JavaScript, выполняющей опрос сервера посредством запуска транзакции Ajax pollTx.

    Visual Designer после настройки транзакций Ajax для элемента "transcriptText"
  12. В окне "Navigator" разверните узел "Page1 > page1 > html1 > head1" и выберите транзакцию Ajax "commentTx".
  13. В окне "Properties" установите для свойства транзакции Ajax "commentTx" postReplace значение customPostReplaceForCommentTx.

    Здесь указывается, что вызов клиентом функции JavaScript customPostReplaceForCommentTx должен осуществляться после получения ответа Ajax, соответствующего транзакции Ajax commentTx и повторной визуализации соответствующих элементов (а именно, только элемента "transcriptText Static Text"). Эта функция JavaScript рассматривается в разделе Добавление JavaScript ниже.
  14. В окне "Navigator" под узлом "Page1 > page1 > html1 > head1" выберите транзакцию Ajax "pollTx".
  15. В окне "Properties" установите для свойств элемента транзакции Ajax "pollTx" inputs и execute значение none.

    В этом действии выполняется явная настройка транзакции Ajax "pollTx" таким образом, что при запуске транзакции Ajax в запрос Ajax не передаются данные каких-либо элементов и не выполняется их обработка на сервере.
  16. Установите для свойства транзакции Ajax "pollTx" postReplace значение customPostReplaceForPollTx, а для свойства replaceElement – значение customReplaceForPollTx.

    Здесь указывается, что функция JavaScript customReplaceForPollTx реализует пользовательскую логику повторной визуализации при получении клиентом ответа Ajax, соответствующего транзакции Ajax "pollTx". Также указывается, что вызов клиентов функции JavaScript customPostReplaceForPollTx должен осуществляться после повторной визуализации соответствующих элементов (а именно, только элемента "transcriptText Static Text"). Эти функции JavaScript рассматриваются в разделе Добавление JavaScript ниже.

Установка свойств JavaScript элементов "Body" и "Form"

  1. В окне "Navigator" под узлом "Page1 > page1 > html1" выберите элемент "body1".
  2. В окне "Properties" установите для свойства onLoad элемента "body1" значение handleOnLoad(), а для свойства onUnload – значение handleOnUnload().

    Эти функции JavaScript рассматриваются в разделе Добавление JavaScript ниже.
  3. В окне "Navigator" под узлом "Page1 > page1 > html1 > body1" выберите элемент "form1".
  4. В окне "Properties" установите для свойства onSubmit элемента "form1" значение return interceptFormSubmit().

    Функция JavaScript interceptFormSubmit рассматривается в разделе Добавление JavaScript ниже. При нажатии пользователем кнопки "Send" или клавиши Enter эта функция JavaScript предотвращает стандартную передачу формы и вместо этого запускает транзакцию Ajax "commentTx".

Добавление JavaScript

Теперь создайте файл JavaScript ajaxchatroom.js.

  1. В окне "Project" разверните узел "Web Pages", щелкните правой кнопкой мыши папку ресурсов и выберите "New > Other".

    Создание файла в папке ресурсов
  2. В мастере создания файла выберите "Other" в списке "Categories" и выберите "Empty File" из списка "Projects", а затем нажмите кнопку "Next".
  3. Назовите файл ajaxchatroom.js и нажмите кнопку "Finish".
  4. Добавьте следующий код JavaScript к файлу:

    Пример кода 6: ajaxchatroom.js
    var pollDelay = 1000;
    var continuePolling = false;
    var mouseDownOnTranscript = false;  //Выполнил ли пользователь "mousedown" (нажатие кнопки мыши) на тексте (включая какую-нибудь полосу прокрутки) без "mouseup" (отпускание кнопки мыши)
    
    function customPostReplaceForCommentTx(element, markup) {
        //Прокрутка к нижней части текста
        var transcriptPanel = document.getElementById('form1:transcriptPanel');
        transcriptPanel.scrollTop = transcriptPanel.scrollHeight;
    
        //Очистка текстового поля
        var commentTextField = document.getElementById('form1:comment');
        commentTextField.value = '';
    
        //Помещение фокуса в текстовое поле
        commentTextField.focus();
    }
    
    function handleOnLoad() {
        //Обработка события "mousedown" на тексте
        var transcriptPanel = document.getElementById('form1:transcriptPanel');
        transcriptPanel.onmousedown = handleMouseDown;
    
        //Обработка события "mouseup" в любом месте страницы
        document.onmouseup = handleMouseUp;
    
        //Отключение автозаполнения для текстового поля
        document.getElementById('form1:comment').setAttribute('autocomplete','off');
    
        //Запуск опроса
        continuePolling = true;
        poll();
    }
    
    function handleOnUnload() {
        //Остановка опроса
        continuePolling = false;
    }
    
    function poll() {
        //Запуск транзакции Ajax "pollTx"
        DynaFaces.Tx.fire('pollTx');
    }
    
    function customReplaceForPollTx(element, markup) {
        //При условии, что пользователь не выполняет операцию, например, выбор текста или прокрутку текста, следует выполнить замену (повторную визуализацию) для этого запроса опроса и прокрутить текст соответствующим образом после замены
        if (!mouseDownOnTranscript) {
            var transcriptPanel = document.getElementById('form1:transcriptPanel');
    
            //scrollTop: Расстояние между верхней частью текста и верхней частью отображаемой в настоящее время части
            //scrollHeight: Общая высота текста, включая любую невидимую вследствие прокрутки часть
            //clientHeight: Высота видимой части текста, если полоса прокрутки существует перед заменой.
            //Полоса прокрутки существует, если "scrollHeight" превышает "clientHeight"
            var scrollbarExistsBeforeReplacement = transcriptPanel.scrollHeight > transcriptPanel.clientHeight;
    
            //Выяснение того, прокручен ли текст вниз до конца, перед заменой
            var scrolledToBottomBeforeReplacement = false;
            if (scrollbarExistsBeforeReplacement) {
                //Текст прокручен до конца вниз, если сумма "scrollTop" и "clientHeight" равна "scrollHeight"
                if (transcriptPanel.scrollTop + transcriptPanel.clientHeight == transcriptPanel.scrollHeight) {
                    scrolledToBottomBeforeReplacement = true;
                }
            }
    
            //Получение "scrollTop" перед заменой
            var scrollTopBeforeReplacement = transcriptPanel.scrollTop;
    
            //Вызов функции замены по умолчанию для выполнения фактической замены содержимого текста
            DynaFaces.replace(element, markup);
    
            //Проверка того, существует ли полоса прокрутки после замены
            var scrollbarExistsAfterReplacement = transcriptPanel.scrollHeight > transcriptPanel.clientHeight;
    
            //Прокрутка к нижней части текста, если он был прокручен до конца вниз перед заменой или если полоса прокрутки не существовала до замены и теперь существует после замены.
            //В противном случае – прокрутка текста к тому же самому месту, которое было до замены
            if (scrolledToBottomBeforeReplacement || (!scrollbarExistsBeforeReplacement && scrollbarExistsAfterReplacement)) {
                transcriptPanel.scrollTop = transcriptPanel.scrollHeight;  //Прокрутка к нижней части текста
            }
            else {
                transcriptPanel.scrollTop = scrollTopBeforeReplacement; //Прокрутка текста к месту, которое было до замены
            }
        }
    }
    
    function handleMouseDown() {
        //Если событие "mousedown" произойдет на полосе прокрутки текста, то IE не будет вызывать соответствующий обработчик события "mouseup" при отпускании кнопки мыши
        //Поэтому значение "True" не присваивается свойству "mouseDownOnTranscript", т.к. оно не будет изменено обратно на "False".
        //Вместо этого выполняется только замена в "customReplaceForPollTx" даже в том случае, если пользователь осуществляет прокрутку текста, т.к. это не вызовет проблему с IE в любом случае
        if (document.all) {
            var transcriptPanel = document.getElementById('form1:transcriptPanel');
            var scrollBarExists = transcriptPanel.scrollHeight > transcriptPanel.clientHeight;
            if (scrollBarExists) {
                if (window.event.offsetX > transcriptPanel.clientWidth) {
                    //Событие "mousedown" на полосе прокрутки
                    return;
                }
            }
        }
        mouseDownOnTranscript = true;
    }
    
    function handleMouseUp() {
        mouseDownOnTranscript = false;
    }
    
    function customPostReplaceForPollTx(element, markup) {
        //Передача следующего запроса опроса
        if (continuePolling) {
            setTimeout(poll, pollDelay);
        }
    }
    
    function interceptFormSubmit() {
        //Если текстовое поле заполнено – запуск "commentTx"
        if (document.getElementById('form1:comment').value != '') {
            DynaFaces.Tx.fire('commentTx');
        }
    
        //Предотвращение стандартной передачи формы
        return false;
    }

    Поскольку для свойства транзакции Ajax "commentTx" postReplace было установлено значение customPostReplaceForCommentTx, вызов клиентом функции customPostReplaceForCommentTx осуществляется после получения ответа Ajax, связанного с соответствующими элементами "commentTx" и "re-rendering" (а именно, только с элементом "transcriptText Static Text"). В технологии Dynamic Faces термины "замена" и "повторная визуализация" используются более или менее взаимозаменяемо. При передаче пользователем комментария посредством нажатия кнопки "Send" или клавиши Enter функция customPostReplaceForCommentTx выполняет прокрутку до нижней части текста, очищает комментарий "Text Field" и выделяет этот комментарий.

    Поскольку для свойства элемента страницы "page1" onLoad было установлено значение handleOnLoad, вызов клиентом функции handleOnLoad осуществляется только после первоначальной загрузки страницы. Эта функция присваивает ссылку на функцию handleMouseDown обработчику событий transcriptPanel.onmousedown, а ссылку на функцию handleMouseUp – обработчику событий document.onmouseup. Функция handleMouseDown реагирует на перемещение указателя мыши вниз в элементе transcriptPanel; функция handleMouseUp реагирует на перемещение указателя мыши вверх в любом месте страницы. Совместная работа этих функций и функции customReplaceForPollTx направлена на предотвращение повторной визуализации в соответствии с запросами на обращение к данным в случае, если пользователь нажал кнопку мыши в любом месте текста (включая любую полосу прокрутки) и еще не отпустил ее. При этом, если пользователь выделяет часть текста (например, при подготовке к копированию), повторная визуализация предотвратит такое выделение; точно так же, если пользователь прокручивает текст в обозревателе FireFox, повторная визуализация текста приведет к неактивности полосы прокрутки. Функция handleMouseUp отвечает за перемещение указателя мыши вверх в объекте document не только в элемент transcriptPanel, поскольку пользователь может нажать кнопку мыши на полосе прокрутки текста, перетащить указатель мыши за пределы области текста и затем отпустить кнопку. В таком случае логика должна реагировать на перемещение указателя мыши вверх даже в том случае, если указатель мыши не находится непосредственно в области текста. Кроме этих функциональных назначений, функция handleOnLoad также выключает функцию автозаполнения обозревателя для комментария "Text Field" и инициирует опрос сервера.

    Функция poll запускает транзакцию Ajax "pollTx", посредством которой запрос Ajax передается на сервер. Соответствующий ответ Ajax вызовет повторную визуализацию элемента "transcriptText Static Text".

    Поскольку для свойства транзакции Ajax "pollTx" replaceElement было установлено значение customReplaceForPollTx, клиент вызывает функцию customReplaceForPollTx вместо функции замены по умолчанию (а именно, DynaFaces.replace) каждый раз при получении клиентом ответа Ajax, связанного с pollTx. Предоставление настраиваемой функции замены customReplaceForPollTx позволяет вызывать функцию замены по умолчанию, которая обычно основывается на выполнении пользователем определенных операций в тексте (а именно, выделения текста или его прокрутки), а также зафиксировать расположение полосы прокрутки перед заменой и надлежащим образом выполнить автоматическую прокрутку после замены. Перед заменой используете свойства scrollTop, scrollHeight и clientHeight элемента transcriptPanel для проверки наличия полосы прокрутки и, при ее наличии, для проверки того, прокручен ли текст до конца. Затем следует делегировать фактическую замену содержимого текста в функцию замены по умолчанию (DynaFaces.replace). После замены необходимо прокрутить текст до того же места, на котором находился указатель мыши до замены, за исключением определенных условий. А именно, текст необходимо прокрутить полностью вниз в случае, если он был прокручен до конца до замены или в случае, если полоса прокрутки существует теперь, но не существовала перед заменой. В первом случае, если автоматическая прокрутка текста вниз не была выполнена, в тексте не будут отображаться какие-либо новые записи. Во втором случае, если автоматическая прокрутка текста вниз не была выполнена, текст останется прокрученным до верхней части, что вынудит пользователя прокрутить текст вниз вручную.

    В функции handleMouseDown обозреватель Internet Explorer требует некоторой дополнительной логики. Если пользователь нажимает кнопку мыши на полосе прокрутки текста, при отпускании этой кнопки обозреватель Internet Explorer не будет вызывать обработчик событий, присвоенный document.onmouseup. В результате невозможно установить для mouseDownOnTranscript значение true, поскольку при отпускании пользователем кнопки мыши не происходит вызова handleMouseUp, и поэтому значением mouseDownOnTranscript останется true. При таких обстоятельствах функция customReplaceForPollTx не будет выполнять повторную визуализацию текста до тех пор, пока какое-либо последующее действие мыши не приведет к запуску функции handleMouseup. Наилучший подход состоит в возвращении от функции handleMouseDown без установки для mouseDownOnTranscript значения true. В результате функция customReplaceForPollTx будет выполнять повторную визуализацию текста в обозревателе Internet Explorer даже в том случае, если пользователь в настоящий момент прокручивает текст. Однако это не приводит к возникновению проблем, поскольку повторная визуализация текста в момент прокручивания его пользователем вызывает неактивность полосы прокрутки только в FireFox, но не в Internet Explorer.

    Поскольку для свойства транзакции Ajax postReplace было установлено значение customPostReplaceForPollTx, клиент вызывает функцию customPostReplaceForPollTx после получения ответа Ajax, связанного с элементом "pollTx", и вызова функции customReplaceForPollTx. При условии, что для переменной continuePolling установлено значение true (в этом случае страница загружается), функция customPostReplaceForPollTx передает следующий запрос на обращение к данным после паузы, определенной переменной pollDelay.

    Поскольку для свойства элемента формы "form1" onSubmit было установлено значение return interceptFormSubmit, клиент вызывает функцию interceptFormSubmit при нажатии пользователем кнопки "Send" или клавиши Enter. При условии, что элемент "Text Field" комментария заполнен, функция interceptFormSubmit запускает транзакцию Ajax "commentTx" (посредством которой передается запрос Ajax) и возвращает значение false для предотвращения стандартной передачи формы.
  5. Разверните раздел "Advanced" в окне "Palette" и перетащите элемент "Script" из раздела "Advanced" в Visual Designer.
  6. В окне "Navigator" выберите элемент сценария "script1" под узлом "Page1 > page1 > html1 >.
  7. В окне "Properties" нажмите кнопку с многоточием (...) для свойства url элемента сценария "script1". В диалоговом окне выберите папку "resources > ajaxchatroom.js such" /resources/ajaxchatroom.js, которая появится в поле URL-адреса, и нажмите кнопку "OK".

    Установка свойства URL-адреса элемента "script1"
    Была выполнена настройка элемента сценария "script1" для создания тега <script> для ранее созданного файла JavaScript ajaxchatroom.js.

Развертывание проекта

Это веб-приложение было протестировано для использования с FireFox и Internet Explorer 7.

  1. В окне "Projects" щелкните правой кнопкой мыши узел проекта и выберите "Run" для сборки, развертывания и запуска веб-приложения.

    В обозревателе открывается страница http://localhost:8080/AjaxChatRoom/.
  2. Введите комментарий в текстовое поле комментария и нажмите клавишу Enter или кнопку "Send".

    В тексте появляется новая запись, выделенная синим цветом, именем пользователя является anonymous1.
  3. В адресной строке обозревателя измените URL-адрес на http://localhost:8080/AjaxChatRoom/?username=jack.

    Теперь предыдущая запись выделена фиолетовым цветом, поскольку теперь пользователь идентифицируется как jack, а не как anonymous1.
  4. Введите другой комментарий в текстовое поле комментария и нажмите клавишу Enter или кнопку "Send". В тексте появляется новая запись, выделенная синим цветом, именем пользователя является jack.
  5. Определите IP-адрес путем открытия окна терминала (или команды) и выполнения одного из следующих действий:
    • Solaris/Linux/MAC. Введите ifconfig -a и нажмите клавишу Enter.
    • Windows. Введите ipconfig и нажмите клавишу Enter.
  6. Откройте второе окно или вкладку обозревателя и введите http://your-ip-address:8080/AjaxChatRoom?username=jill.

    Записи, переданные пользователями anonymous1 и jack, выделяются фиолетовым цветом.
  7. Введите другой комментарий в текстовое поле комментария и нажмите клавишу Enter или кнопку "Send".

    В тексте появляется новая запись, выделенная синим цветом, именем пользователя является jill.
  8. Вернитесь к первоначальному окну или вкладке обозревателя.

    Появляется запись, переданная пользователем jill, выделенная фиолетовым цветом.
  9. Продолжайте беседу между пользователями jack и jill до тех пор, пока в тексте не отобразится полоса прокрутки.
  10. Перейдите к началу содержимого текста, прокручивая страницу вниз, как при повторном чтении начала беседы. Подождите несколько секунд и отпустите кнопку мыши.

    Поведение несколько отличается от режима работы обозревателя. При работе с обозревателем FireFox при нажатии кнопки мыши не выполняется повторной визуализации текста в соответствии с запросами на обращение к данным. При работе с обозревателем Internet Explorer при нажатии кнопки мыши продолжается повторная визуализация текста. Это связано с тем, что в Internet Explorer функция handleMouseDown не выполняет установку значения true для переменной mouseDownOnTranscript. Это тонкое различие в режиме работы не может быть обнаружено при тестировании одного приложения, как описано в этом разделе. Для наблюдения различий в режиме работы следует занести в список для беседы дополнительного пользователя, который будет направлять комментарии во время выполнения этого действия.
  11. Выделите часть текста, не отпуская при этом кнопку мыши. Нажмите комбинацию клавиш для копирования текста в буфер обмена. Затем отпустите кнопку мыши и обратите внимание, что после этого выделение текста пропадает.

    При нажатии кнопки мыши в тексте не выполняется повторная визуализация в соответствии с запросами на обращение к данным. Однако после отпускания кнопки мыши последующие запросы вызывают повторную визуализацию текста. Повторная визуализация текста вызывает отмену любого выделения. Это приложение можно расширить путем добавления логики в функцию customReplaceForPollTx для сбора информации о выделении перед заменой и восстановления этого выделения после замены. В таком случае при выделении пользователем некоторого текста это выделение может быть отменено в соответствии со следующим перемещением курсора мыши вниз в любое место документа. Для этого можно добавить функцию, посредством которой отменяется выделение всего текста, и присвоить ссылку на эту функцию обработчику событий document.onmousedown.

Дополнительная информация



Bookmark this page

del.icio.us furl simpy slashdot technorati digg
Companion
Projects:
MySQL Database Server   GlassFish Community: an Open Source Application Server   Open Solaris  Open JDK: an Open SourceJDK   Mobile & Embedded Community     Sponsored by 
Sponsored by Sun Microsystems