|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Глава 7 Способы организации диалогового режима работы сценариев В этой главе на примере работы с записной книжкой будут рассмотрены три способа организации из сценария диалога с пользователем. Во-первых, мы еще раз подробно остановимся на том, как можно использовать параметры командной строки для запуска различных заданий из многозадачного WS-файла, который в нашем случае будет реализовывать несколько функций для работы с записной книжкой. Во-вторых, для того же WS-файла мы создадим кнопочное (командное) меню, в котором пользователь сможет выбрать нужное ему действие с помощью ввода определенных символов в диалоговом окне. Наконец, будет показано, как можно организовать в сценарии полноценный пользовательский интерфейс с помощью HTML-форм и браузера Internet Explorer. Многозадачный сценарий для работы с записной книжкой В качестве примера рассмотрим сценарий для работы с записной книжкой в XML-формате (структура файла book.xml, в котором хранится записная книжка, описана в предыдущей главе), в котором будут реализованы следующие функции: ? просмотр всех записей в алфавитном порядке; ? поиск записей по фамилии; ? добавление и удаление записей. Каждая из этих задач реализуется в виде отдельного задания в файле PhoneBook.wsf (листинг 7.1). Листинг 7.1. Схема многозадачного файла PhoneBook.wsf<package> <!-- ****************** Просмотр всех записей ******************* --> <job id="SortName"> … </job> <!-- *************** поиск записей по фамилии ************** --> <job id="FindName"> … </job> <!-- *************** удаление записи по фамилии *************** --> <job id="DelRec"> … </job> <!-- *************** добавление записи *************** --> <job id="AddRec"> … </job> </package> Некоторые функции (например, настройка пути к XML-файлу) должны присутствовать во всех заданиях, поэтому такие общие функции мы вынесем в отдельный файл Usage.js, который будет подключаться в каждом из заданий следующим образом: <script language="JScript" src="Usage.js"/> В файл Usage.js помещены следующие функции: ? конструктор объекта Person(одна запись из книжки); ? функция GetTagVal(obj, tgName), которая возвращает значения тега tgNameXML-элемента obj; ? функция PersonToArray(XNode), которая заполняет поля экземпляра PersonRecобъекта Personданными из соответствующих XML-элементов и добавляет сформированную запись в массив PersonArr; ? функции TopReport(Mess)и BottomReport(Mess), с помощью которых в выходной файл печатается заголовок отчета и итоговая информация соответственно; ? функция PrintPerson(PersRec), в которой происходит вывод данных из полей объекта PersonRecв выходной файл; ? функция MakeOut(), которая обеспечивает запуск Блокнота и открывает в нем выходной файл; ? функция InitPath(), в которой строятся пути к XML-файлу, содержащему данные, и выходному файлу. Usage.js объявляются глобальные переменные и константы. Полностью содержимое файла Usage.js приведено в листинге 7.2. Листинг 7.2. Общие функции для работы с записной книжкой/*******************************************************************/ /* Имя: Usage.js */ /* Язык: JScript */ /* Описание: Общие функции для записной книжки */ /*******************************************************************/ //Объявляем переменные var WshShell,FSO, BasePath, //Путь к текущему каталогу PathBook, //Путь к файлу с данными PathOut, //Путь к выходному файлу FBook, //Файл с данными FOut, //Выходной файл NomRec=0, //Счетчик количества записей PersonRec, //Объект для хранения данных об одном человеке PersonArr; //Массив для хранения объектов PersonRec ForWriting=2; //Константа для создания выходного файла //Инициализируем константы для диалоговых окон var vbYesNo=4,vbQuestion=32,vbInformation=64,vbYes=6,vbOkOnly=0; //Конструктор объекта Person function Person(LastName,Name,Phone,Street,House,App,Note) { this.LastName=LastName; //Фамилия this.Name=Name; //Имя this.Phone=Phone; //Телефон this.Street=Street; //Улица this.House=House; //Дом this.App=App; //Квартира this.Note=Note; //Примечание } //Определение значения тега tgName XML-элемента obj function GetTagVal(obj, tgName) { var ElemList; //Создаем коллекцию дочерних для obj элементов, которые //задаются тегом tgName ElemList=obj.getElementsByTagName(tgName); //Проверяем, есть ли в коллекции ElemList элементы if (ElemList.length>0) //Возвращаем значение тега tgName return ElemList.item(0).text else return ""; } //Заполнение нового элемента массива function PersonToArray(XNode) { //Создаем новый экземпляр PersonRec объекта Person PersonRec=new Person(); //Заполняем поля объекта PersonRec PersonRec.LastName=GetTagVal(XNode,"LastName"); PersonRec.Name=GetTagVal(XNode,"Name"); PersonRec.Phone=GetTagVal(XNode,"Phone"); PersonRec.Street=GetTagVal(XNode,"Street"); PersonRec.House=GetTagVal(XNode,"House"); PersonRec.App=GetTagVal(XNode,"App"); PersonRec.Note=GetTagVal(XNode,"Note"); //Сохраняем объект PersonRec в массиве PersonArr[PersonArr.length]=PersonRec; } //Запись в выходной файл заголовка отчета function TopReport(Mess) { FOut.WriteLine(Mess); FOut.WriteLine("--------------------"); FOut.WriteLine(""); } //Запись в выходной файл итоговой информации function BottomReport(Mess) { FOut.WriteLine(Mess); } //Запись данных из объекта Person в выходной файл function PrintPerson(PersRec) { FOut.WriteLine("Фамилия: "+PersRec.LastName); FOut.WriteLine("Имя: "+PersRec.Name); FOut.WriteLine("Телефон: "+PersRec.Phone); FOut.WriteLine("Улица: "+PersRec.Street); FOut.WriteLine("Дом: "+PersRec.House); FOut.WriteLine("Кв.: "+PersRec.App); FOut.WriteLine("Заметки: "+PersRec.Note); FOut.WriteLine("*********************************"); NomRec++; } //Просмотр содержимого выходного файла в Блокноте function MakeOut() { //Закрываем выходной файл FOut.Close(); //Открываем выходной файл в Блокноте WshShell.Run("notepad "+PathOut,1); } //Построение путей к файлам function InitPath() { BasePath=WshShell.CurrentDirectory+"\\"; //Путь к файлу с данными PathBook=BasePath+"book.xml", //Путь к выходному файлу PathOut=BasePath+"out.txt"; } /************* Конец *********************************************/ Также в отдельный файл WSHInputBox.vbs мы поместим функцию WSHinputBox(Message, Title)на языке VBScript, с помощью которой из JScript-сценариев будет выводиться диалоговое окно со строкой ввода (напомним, что ни язык JScript, ни объектная модель WSH такой функции не предоставляют): Function WSHInputBox(Message,Title) 'Выводим диалоговое окно со строкой ввода WSHInputBox = InputBox(Message,Title) End Function Сами задания из файла PhoneBook.wsf составлены (с некоторыми изменениями, на которых мы подробно останавливаться не будем) из одиночных сценариев, которые были рассмотрены в предыдущей главе: см. листинг 6.3 (просмотр всех записей в алфавитном порядке), листинг 6.4 (добавление записей) и листинг 6.5 (поиск записей по фамилии и удаление записей). В листинге 7.3 приводится полный текст сценария PhoneBook.wsf. Листинг 7.3. Многозадачный сценарий PhoneBook.wsf для работы с записной книжкой<package> <!-- ****************** Просмотр всех записей ******************* --> <job id="SortName"> <script language="JScript" src="usage.js"/> <script language="JScript"> //Создание массива объектов Person function FileToArray() { var XML,Root,NomRec,CurrNode,ex,i; //Создаем массив PersonArr PersonArr=new Array(); //Создаем объект XML DOM XML = WScript.CreateObject("Msxml.DOMDocument"); //Загружаем XML-документ из файла XML.load(PathBook); //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XML.documentElement; //Перебираем все дочерние элементы первого уровня вложенности //для корневого элемента for (i=1; i<=Root.childNodes.length-1;i++) { //Выделяем в коллекции XML-элементов i-й элемент CurrNode=Root.childNodes.item(i); //Добавляем новый элемент в массив объектов Person PersonToArray(CurrNode); } } //Сортировка массива и вывод его содержимого в выходной файл function ListPersonArray() { var i; //Сортировка массива по фамилии PersonArr.sort(SortLastName); //Цикл по всем элементам массива PersonArr for (i=0;i<=PersonArr.length-1;i++) { //Запись информации в выходной файл PrintPerson(PersonArr[i]); } } //Функция для сортировки массива по фамилии function SortLastName(Pers1,Pers2) { if (Pers1.LastName<Pers2.LastName) return -1; else if (Pers1.LastName==Pers2.LastName) return 0; else return 1; } //Основная запускная функция function Main() { //Создаем объект WshShell WshShell = WScript.CreateObject("WScript.Shell"); //Определяем пути к файлам InitPath(); //Создаем объект FileSystemObject FSO=WScript.CreateObject("Scripting.FileSystemObject"); //Открываем выходной файл для записи FOut=FSO.OpenTextFile(PathOut,ForWriting,true); //Печатаем заголовок отчета TopReport("Список всех записей, сортировка по фамилии"); //Считываем данные из файла в массив FileToArray(); //Записываем информацию из массива в выходной файл ListPersonArray(); //Печатаем итоговую информацию BottomReport("Всего записей: "+PersonArr.length); //Открываем выходной файл в Блокноте MakeOut(); } //Запускаем основную функцию Main(); </script> </job> <!-- *************** Поиск записей по фамилии ************** --> <job id="FindName"> <script language="VBScript" src="WSHInputBox.vbs"/> <script language="JScript" src="usage.js"/> <script language="JScript"> //Поиск в XML-файле нужных записей и сохранение их в //массиве PersonArr function RecordsToArray(LastName) { var XMLDoc,Root,sSelect,i,Parent,NodeList; //Создаем массив PersonArr PersonArr=new Array(); //Создаем объект DOMDocument XMLDoc = WScript.CreateObject("Msxml.DOMDocument"); //Загружаем XML-файл XMLDoc.load(PathBook); //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XMLDoc.documentElement; //Формируем строку для поиска фамилии sSelect="Person/LastName[text()='"+LastName+"']"; //Создаем коллекцию NodeList всех элементов LastName, //значение которых совпадает со значением переменной LastName NodeList=XMLDoc.documentElement.selectNodes(sSelect); if (NodeList.length==0) {//Коллекция NodeList пуста //Выводим диалоговое окно с сообщением WshShell.Popup("Фамилия "+ LastName+ " не найдена!", 0, "Записная книжка",vbInformation+vbOkOnly); //Завершаем выполнение задания WScript.Quit(); } else { //Требуемая фамилия найдена //Цикл по всем найденным элементам LastName for (i=0;i<=NodeList.length-1;i++) { //Определяем родительский элемент (Person) для найденного //элемента LastName Parent=NodeList.item(i).parentNode; //Добавляем новый элемент в массив объектов Person PersonToArray(Parent); } } } //Вывод в выходной файл информации о найденных записях function PrintAllFind() { var i; for (i=0;i<PersonArr.length;i++) { PrintPerson(PersonArr[i]); } } //Основная запускная функция function Main() { var LastName; //Создаем объект WshShell WshShell = WScript.CreateObject("WScript.Shell"); //Определяем пути к файлам InitPath(); //Создаем объект FileSystemObject FSO=WScript.CreateObject("Scripting.FileSystemObject"); //Открываем выходной файл для записи FOut=FSO.OpenTextFile(PathOut,ForWriting,true); //Печатаем заголовок отчета TopReport("Поиск записей"); //Вводим фамилию для поиска LastName=WSHInputBox("Введите фамилию для поиска:","Записная книжка") //Ищем в XML-файле нужные записи и сохраняем их в массиве PersonArr RecordsToArray(LastName); //Выводим все найденные записи из массива PersonArr в выходной файл PrintAllFind(LastName); //Печатаем итоговую информацию BottomReport("Всего найдено: "+PersonArr.length); //Открываем выходной файл в Блокноте MakeOut(); } //Запускаем основную функцию Main(); </script> </job> <!-- *************** Удаление записи по фамилии *************** --> <job id="DelRec"> <script language="VBScript" src="WSHInputBox.vbs"/> <script language="JScript" src="usage.js"/> <script language="JScript"> //Поиск фамилии в записной книжке и удаление всех //реквизитов, относящихся к этой фамилии function FindAndDelRecord(LastName) { var Root,sSelect,i,Parent,NodeList; //Создаем объект DOMDocument XMLDoc = WScript.CreateObject("Msxml.DOMDocument"); //Загружаем XML-файл XMLDoc.load(PathBook); //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XMLDoc.documentElement; //Формируем строку для поиска фамилии sSelect="Person/LastName[text()='"+LastName+"']"; //Создаем коллекцию NodeList всех элементов LastName, //значение которых совпадает со значением переменной LastName NodeList=XMLDoc.documentElement.selectNodes(sSelect); if (NodeList.length==0) //Коллекция NodeList пуста //Выводим диалоговое окно с сообщением WshShell.Popup("Фамилия "+LastName+ " не найдена!", 0, "Записная книжка",vbInformation+vbOkOnly); else { //Требуемая фамилия найдена //Цикл по всем найденным элементам LastName for (i=0;i<=NodeList.length-1;i++) { //Определяем родительский элемент (Person) для найденного //элемента LastName Parent=NodeList.item(i).parentNode; //Удаляем элемент Person вместе со всеми его дочерними элементами Root.removeChild(Parent); //Выводим диалоговое окно с сообщением WshShell.Popup("Запись удалена!",0, "Записная книжка",vbInformation+vbOkOnly); } //Сохраняем содержимое XML-файла на диске XMLDoc.save(PathBook); } } //Основная запускная функция function Main() { var LastName,Res; //Создаем объект WshShell WshShell = WScript.CreateObject("WScript.Shell"); //Определяем пути к файлам InitPath(); LastName=WSHInputBox("Введите фамилию для удаления:","Записная книжка") //Запрос на удаление записи Res=WshShell.Popup("Удалить фамилию "+LastName+ " из \n"+PathBook+"?",0, "Записная книжка",vbQuestion+vbYesNo); if (Res==vbYes) { //Нажата кнопка Да //Ищем в книжке нужную фамилию и удаляем относящуюся к //ней запись FindAndDelRecord(LastName); } } //Запускаем основную функцию Main(); </script> </job> <!-- *************** Добавление записи *************** --> <job id="AddRec"> <script language="VBScript" src="WSHInputBox.vbs"/> <script language="JScript" src="Usage.js"/> <script language="JScript"> //Ввод значений полей объекта PersonRec function MakePersonRec() { //Создаем новый экземпляр PersonRec объекта Person PersonRec=new Person(); //Вводим значения полей добавляемой записи с помощью диалогового //окна со строкой ввода PersonRec.LastName=WSHInputBox("Введите фамилию","Добавление записи"); PersonRec.Name=WSHInputBox("Введите имя","Добавление записи"); PersonRec.Phone=WSHInputBox("Введите телефон","Добавление записи"); PersonRec.Street=WSHInputBox("Введите улицу","Добавление записи"); PersonRec.House=WSHInputBox("Введите дом","Добавление записи"); PersonRec.App=WSHInputBox("Введите квартиру","Добавление записи"); PersonRec.Note=WSHInputBox("Введите примечание","Добавление записи"); } //Сохранение данных из объекта PersonRec в XML-файле function RecordToFile(PersRec) { var Root,NewElem,s; //Создаем объект DOMDocument XMLDoc = WScript.CreateObject("Msxml.DOMDocument"); //Загружаем XML-файл XMLDoc.load(PathBook); //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XMLDoc.documentElement; //Создаем XML-элемент Person NewElem=XMLDoc.createElement("Person"); //Добавляем новый элемент в XML-файл Root.appendChild(NewElem); //Сохраняем в переменной Root ссылку на последний добавленный //элемент Person Root=Root.lastChild; //Создаем элемент LastName NewElem=XMLDoc.createElement("LastName"); //Добавляем новый элемент в XML-файл (внутри элемента Person) Root.appendChild(NewElem); //Подставляем в качестве содержимого элемента LastName //значение поля LastName объекта PersRec Root.lastChild.text=PersRec.LastName; //Создаем элемент Name NewElem=XMLDoc.createElement("Name"); //Добавляем новый элемент в XML-файл (внутри элемента Person) Root.appendChild(NewElem); //Подставляем в качестве содержимого элемента Name //значение поля Name объекта PersRec Root.lastChild.text=PersRec.Name; //Создаем элемент Phone NewElem=XMLDoc.createElement("Phone"); //Добавляем новый элемент в XML-файл (внутри элемента Person) Root.appendChild(NewElem); //Подставляем в качестве содержимого элемента Phone //значение поля Phone объекта PersRec Root.lastChild.text=PersRec.Phone; //Создаем элемент Street NewElem=XMLDoc.createElement("Street"); //Добавляем новый элемент в XML-файл (внутри элемента Person) Root.appendChild(NewElem); //Подставляем в качестве содержимого элемента Street //значение поля Street объекта PersRec Root.lastChild.text=PersRec.Street; //Создаем элемент House NewElem=XMLDoc.createElement("House"); //Добавляем новый элемент в XML-файл (внутри элемента Person) Root.appendChild(NewElem); //Подставляем в качестве содержимого элемента House //значение поля House объекта PersRec Root.lastChild.text=PersRec.House; //Создаем элемент App NewElem=XMLDoc.createElement("App"); //Добавляем новый элемент в XML-файл (внутри элемента Person) Root.appendChild(NewElem); //Подставляем в качестве содержимого элемента App //значение поля House объекта PersRec Root.lastChild.text=PersRec.App; //Создаем элемент Note NewElem=XMLDoc.createElement("Note"); //Добавляем новый элемент в XML-файл (внутри элемента Person) Root.appendChild(NewElem); //Подставляем в качестве содержимого элемента App //значение поля House объекта PersRec Root.lastChild.text=PersRec.Note; //Сохраняем содержимое XML-файла на диске XMLDoc.save(PathBook); } //Добавление новой записи в книжку function AddRecord() { //Заполняем поля объекта PersonRec MakePersonRec(); //Сохраняем данные из объекта PersonRec в XML-файл RecordToFile(PersonRec); } //Построение путей к файлам function InitPath() { BasePath=WshShell.CurrentDirectory+"\\"; //Путь к файлу с данными PathBook=BasePath+"book.xml"; } //Основная запускная функция function Main() { var Res; //Создаем объект WshShell WshShell = WScript.CreateObject("WScript.Shell"); //Определяем пути к файлам InitPath(); //Запрос на создание нового ключа Res=WshShell.Popup("Добавить запись в \n"+PathBook+"?",0, "Записная книжка",vbQuestion+vbYesNo); if (Res==vbYes) { //Нажата кнопка Да //Добавляем новую запись в книжку AddRecord(); //Выводим информацию на экран WshShell.Popup("Новая запись\n\n"+PersonRec.LastName+" "+ PersonRec.Name+"\n"+PersonRec.Phone+"\n"+ PersonRec.Street+", "+PersonRec.House+"-"+PersonRec.App+"\n\n"+ "добавлена!",0, "Записная книжка",vbInformation+vbOkOnly); } } //Запускаем основную функцию Main(); </script> </job> </package> Итак, у нас теперь имеется многозадачный WS-файл PhoneBook.wsf, обеспечивающий необходимую функциональность для работы с записной книжкой, и следующая задача состоит в организации более или менее удобного диалога с пользователем для запуска заданий из этого файла. Обработка параметров командной строки Самый простой вариант организовать диалог с пользователем состоит в использовании параметров командной строки. Напомним, что объектная модель WSH предоставляет несколько методов, которые позволяют производить анализ именных и безымянных параметров (см. разд. "Работа с параметрами командной строки сценария" главы 2), с которыми был запущен сценарий, а в схеме WS XML есть несколько специальных элементов ( <runtime>, < named>, <unnamed>, <description>и <example>), предназначенных для быстрого создания встроенной справки, описывающей синтаксис сценария и смысл каждого из параметров. Для нашего примера мы создадим сценарий ArgMenu.wsf, в котором будем анализировать аргументы командной строки и в зависимости от них запускать то или иное задание из файла PhoneBook.wsf. Названия и назначения именных параметров, которые мы будем использовать, приведены в табл. 7.1. Таблица 7.1. Параметры командной строки сценария для работы с записной книжкой
Если запустить сценарий ArgMenu.wsf вообще без параметров, либо с параметрами, не указанными в табл. 7.1, то на экран будет выведена встроенная справка (рис. 7.1). Рис. 7.1. Встроенная справка для сценария ArgMenu.wsf В листинге 7.4 приводится полный текст сценария ArgMenu.wsf. Листинг 7.4. Обработка параметров командной строки сценария для работы с записной книжкой <job id="ArgMenu"> <runtime> <description> Сценарий для работы с телефонной книжкой </description> <named name="L" helpstring="Просмотр содержимого книжки" type="simple" required="false"/> <named name="F" helpstring="Поиск по фамилии" type="simple" required="false"/> <named name="A" helpstring="Добавление записи" type="simple" required="false"/> <named name="D" helpstring="Удаление записи" type="simple" required="false"/> </runtime> <script language="JScript"> var WshShell; WshShell=WScript.CreateObject("WScript.Shell"); if ((WScript.Arguments.Named.Exists("L")) || (WScript.Arguments.Named.Exists("l"))) { WshShell.Run("wscript PhoneBook.wsf //Job:SortName"); WScript.Quit(); } if ((WScript.Arguments.Named.Exists("F")) || (WScript.Arguments.Named.Exists("f"))) { WshShell.Run("wscript PhoneBook.wsf //Job:FindName"); WScript.Quit(); } if ((WScript.Arguments.Named.Exists("A")) || (WScript.Arguments.Named.Exists("a"))) { WshShell.Run("wscript PhoneBook.wsf //Job:AddRec"); WScript.Quit(); } if ((WScript.Arguments.Named.Exists("D")) || (WScript.Arguments.Named.Exists("d"))) { WshShell.Run("wscript PhoneBook.wsf //Job:DelRec"); WScript.Quit(); } //Ни один из нужных аргументов не был указан, выводим //описание параметров WScript.Arguments.ShowUsage(); </script> </job> Теперь, если понадобится ввести дополнительную функцию при работе с записной книжкой (например, поиск по номеру телефона), нужно будет в файл PhoneBook.wsf добавить задание с новым идентификатором, а в файл ArgMenu.wsf — обработку нового параметра командной строки. Организация диалога с помощью кнопочного меню Вторым вариантом организации диалога, который мы рассмотрим, является кнопочное (командное) меню. Принцип его работы в нашем примере остается практически тем же, что и при описанной выше обработке аргументов командной строки — пользователь должен в диалоговом окне ввести символ, соответствующий одной из описанных в этом окне команд (рис. 7.2). Этот символ анализируется в сценарии, и в зависимости от его значения вызывается то или иное задание из файла PhoneBook.wsf. Рис. 7.2. Кнопочное меню для работы с записной книжкой Диалоговое окно, показанное на рис. 7.2, выводится в цикле while, в котором с помощью оператора switchанализируется введенный пользователем символ. Выход из цикла совершается, если введенный символ совпадает с "q" или "Q". Текст сценария ComMenu.wsf, реализующего кнопочное меню для работы с записной книжкой, приводится в листинге 7.5. Листинг 7.5. Командное меню для работы с записной книжкой<job id="ComMenu"> <script language="VBScript" src="WSHInputBox.vbs"/> <script language="JScript"> var WshShell,SMenu,Res; WshShell=WScript.CreateObject("WScript.Shell"); SMenu="[L] - Просмотр содержимого книжки\n"; SMenu+="[F] - Поиск по фамилии\n"; SMenu+="[A] - Добавление записи\n"; SMenu+="[D] - Удаление записи\n"; SMenu+="[Q] - Выход из сценария\n"; SMenu+="\n\nКоманда:"; Res=""; while ((Res!="q") && (Res!="Q")) { Res=WSHInputBox(SMenu,"Записная книжка"); switch (Res) { case "L": { WshShell.Run("wscript PhoneBook.wsf //Job:SortName",1,true); break; } case "l": { WshShell.Run("wscript PhoneBook.wsf //Job:SortName",1,true); break; } case "F": { WshShell.Run("wscript PhoneBook.wsf //Job:FindName",1,true); break; } case "f": { WshShell.Run("wscript PhoneBook.wsf //Job:FindName",1,true); break; } case "A": { WshShell.Run("wscript PhoneBook.wsf //Job:AddRec",1,true); break; } case "a": { WshShell.Run("wscript PhoneBook.wsf //Job:AddRec",1,true); break; } case "D": { WshShell.Run("wscript PhoneBook.wsf //Job:DelRec",1,true); break; } case "d": { WshShell.Run("wscript PhoneBook.wsf //Job:DelRec",1,true); break; } } } </script> </job> Однозадачный сценарий для работы с записной книжкой Как мы видим из вышеприведенных примеров, ни объектная модель WSH, ни языки JScript и VBScript не предоставляют средств для создания полноценного графического интерфейса пользователя. Тем не менее, такой интерфейс в сценариях WSH создать можно. Мы продемонстрируем это на примере еще одного сценария (состоящего из однозадачного JScript-файла) для работы с записной книжкой, в котором для диалога с пользователем будет организована пользовательская форма с несколькими кнопками и текстовыми полями ввода. Для создания этой формы и работы с ней будут использоваться HTML-файл и браузер Internet Explorer. Использование Internet Explorer для создания диалоговых окон Процесс создания сценария WSH, использующего Internet Explorer в качестве интерфейса, можно условно разделить на несколько этапов: ? создание HTML-формы в отдельном файле; ? написание функции для сценария WSH, в которой будет производиться вывод на экран построенной формы; ? написание части сценария, в которой будет реализована необходимая функциональность (например, обмен информацией между формой и внешним файлом с данными, корректное отображение данных в форме и т.д.); ? добавление в сценарий функций-обработчиков событий, связанных с поведением браузера Internet Explorer; ? добавление в сценарий функций-обработчиков событий, которые генерируются элементами управления в форме. Ниже мы рассмотрим каждый из этих этапов на примере создания сценария IEPhoneBook.js для работы с записной книжкой, которая хранится, как и прежде, в XML-файле book.xml. Разработка HTML-формы для диалогового окна В качестве интерфейса записной книжки мы создадим диалоговое окно (пользовательскую форму), которое показано на рис. 7.3. Рис. 7.3. Диалоговое окно для работы с записной книжкой Эта форма реализуется с помощью HTML-файл Phone.htm, который полностью приведен в листинге 7.6. В самом начале файла Phone.htm ставится тег <html>, указывающий на то, что содержимым файла является текст в формате HTML, а также теги <head>и </head>, внутри которых задаются используемая кодировка ( charset=windows-1251) и заголовок формы (теги <title>и </title>): <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <title>Форма для записной книжки</title> </head> Для того чтобы задать цвет формы, в теге <body>используется атрибут bgcolorсо значением " silver": <body bgcolor="silver" scroll="no"> Атрибут scroll="no"указывает на то, что в диалоговом окне не должно быть полос прокрутки. Наша форма состоит из семи текстовых полей ввода (табл. 7.2) и восьми кнопок (табл. 7.3). Таблица 7.2. Поля ввода диалогового окна для работы с записной книжкой
Таблица 7.3. Кнопки диалогового окна для работы с записной книжкой
Команды, создающие форму, находятся внутри тегов <form>и </form>. Сами текстовые поля ввода и кнопки создаются в HTML-файле с помощью одного и того же тега <input>. Внутри этого тега нужно указать несколько атрибутов: ? type— определяет тип элемента управления (для поля ввода type="text", для кнопки type="button"); ? name— задает имя элемента управления; ? size— определяет длину строки поля ввода в символах; ? value— задает надпись на кнопке. Для того чтобы поля ввода располагались точно друг под другом, мы поместим их в таблицу с невидимыми границами, состоящую из двух столбцов: в первом находится описание (метка) для поля, во втором — сам элемент управления. Таблица в HTML-файле создается с помощью парных тегов <table>и </table>, внутри которых приводятся теги <tr>и </tr>, задающие начало и конец одной строки таблицы соответственно: <table border="0" width="100%" style="font-family:Arial; font-size:10pt"> <tr> </tr> </table> Здесь аргумент borderзадает ширину границ таблицы (в нашем случае границы невидимы), а в аргументе styleуказываются название и размер шрифта, которым будет выводиться содержимое таблицы. В свою очередь, внутри тегов <tr>и </tr>находятся теги <td>и </td>, определяющие одну ячейку таблицы, например: <tr> <td width="15%">Фамилия</td> <td width="85%"><input type="text" name="txtLastName" size="50"></td> </tr> Для тегов <td>указывается аргумент width, задающий ширину строки в процентах от общей ширины строки. Кнопки в форме выводятся друг за другом, нужное расстояние между ними достигается с помощью неразрывных пробелов (escape-последовательность  ), например: <input type="button" value="<" name="btnPrevious"> <input type="button" value="Новая запись" name="btnNew"> Листинг 7.6. Описание формы в HTML-файле (Phone.htm) <html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <title>Форма для записной книжки</title> </head> <body bgcolor="silver" scroll="no"> <form name="MainForm"> <table border="0" width="100%" style="font-family:Arial; font-size:10pt"> <tr> <td width="15%">Фамилия</td> <td width="85%"><input type="text" name="txtLastName" size="50"></td> </tr> <tr> <td>Имя</td> <td><input type="text" name="txtName" size="50"></td> </tr> <tr> <td>Телефон</td> <td><input type="text" name="txtPhone" size="15"></td> </tr> <tr> <td>Улица</td> <td><input type="text" name="txtStreet" size="50"></td> </tr> <tr> <td>Дом</td> <td><input type="text" name="txtHouse" size="10"></td> </tr> <tr> <td>Кв.</td> <td><input type="text" name="txtApp" size="5"></td> </tr> <tr> <td>Примечание</td> <td><input type="text" name="txtNote" size="80"></td> </tr> </table> <br> <input type="button" value="<<" name="btnFirst"> <input type="button" value="<" name="btnPrevious"> <input type="button" value="Новая запись" name="btnNew"> <input type="button" value="Записать" name="btnSave"> <input type="button" value="Отменить" name="btnCancel"> <input type="button" value="Удалить" name="btnDelete"> <input type="button" value=">" name="btnNext"> <input type="button" value=">>" name="btnFinal"> </form> </body> </html> Создание объекта для обмена данными между XML-файлом и формой В отличие от рассмотренного выше сценария PhoneBook.wsf, в сценарии IEPhoneBook.js функции для работы с записной книжкой не будут разделены по разным заданиям, поэтому для более четкой организации сценария мы воспользуемся объектно-ориентированным подходом и создадим два объекта Personи ListPersons, методы которых и будут осуществлять обработку данных и связь между XML-файлом и пользовательской формой. Как и раньше, в свойствах объекта Personбудет храниться запись об одном человеке. Кроме этого, мы добавим в объект Personметод LoadDialog, который будет заполнять поля ввода в форме данными из соответствующих свойств объекта Person: //Конструктор объекта Person function Person() { //Инициализируем свойства объекта this.LastName=""; this.Name=""; this.Phone=""; this.Street=""; this.House=""; this.App=""; this.Note=""; //Устанавливаем для метода LoadDialog указатель на //функцию Person_LoadDialog this.LoadDialog=Person_LoadDialog; } //Заполнение полей в форме для текущей записи function Person_LoadDialog() { //Заполняем поля ввода в форме значениями соответствующих //свойств объекта Person doc.all.txtLastName.value = this.LastName; doc.all.txtName.value=this.Name; doc.all.txtPhone.value=this.Phone; doc.all.txtStreet.value=this.Street; doc.all.txtHouse.value=this.House; doc.all.txtApp.value = this.App; doc.all.txtNote.value = this.Note; } Принцип доступа к полям ввода формы по их именам, который используется в методе LoadDialog(), объясняется ниже (см. разд. "Обработка событий, генерируемых элементами управления формы"). Основным объектом, который обеспечивает обмен данными между XML-файлом записной книжки и разработанной нами формой, является объект ListPersons. Этот объект будет содержать три свойства и десять методов. Первым свойством объекта ListPersonsмы сделаем массив PersonArrобъектов Person; этот массив будет служить промежуточным буфером при чтении данных из XML-файла для отображения в форме и при записи измененных данных из формы в файл. В остальных двух свойствах СurRecordи IsChangedобъекта ListPersonsбудут соответственно храниться номер текущей записи и логическое значение ( trueили false), являющееся признаком того, были ли изменены пользователем данные в форме. Назначение методов объекта ListPersonsясно из комментариев, которые приведены в конструкторе этого объекта (листинг 7.7). Листинг 7.7. Конструктор объекта ListPersons function ListPersons() { // Свойства объекта //Создаем массив PersonArr экземпляров объекта Person this.PersonArr = new Array(); //Инициализируем номер текущей записи this.CurRecord = 0; //Сбрасываем признак изменения данных в форме this.IsChanged = false; // Методы объекта //Устанавливаем для методов указатели на соответствующие функции this.FileToArray=ListPersons_FileToArray; this.SaveData=ListPersons_SaveData; this.LoadDialog=ListPersons_LoadDialog; this.RefreshDialog=ListPersons_RefreshDialog; this.NextRecord=ListPersons_NextRecord; this.PreviousRecord=ListPersons_PreviousRecord; this.FirstRecord=ListPersons_FirstRecord; this.FinalRecord=ListPersons_FinalRecord; this.NewRecord=ListPersons_NewRecord; this.DelRecord = ListPersons_DelRecord; } Текст всех методов объекта ListPersonsс подробными комментариями приведен в листинге 7.8. Листинг 7.8. Методы объекта ListPersons //Считывание данных из XML-файла в массив объектов Person function ListPersons_FileToArray() { var Root,CurrNode,i; //Создаем объект XML DOM XML = WScript.CreateObject("Msxml.DOMDocument"); //Загружаем XML-документ из файла XML.load(PathBook); //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XML.documentElement; //Обнуляем массив PersonArr this.PersonArr.length=0; //Перебираем все дочерние элементы первого уровня вложенности //для корневого элемента for (i=1; i<=Root.childNodes.length-1;i++) { //Выделяем в коллекции XML-элементов i-й элемент CurrNode=Root.childNodes.item(i); //Создаем новый экземпляр PersonRec объекта Person PersonRec=new Person(); //Заполняем поля объекта PersonRec PersonRec.LastName=GetTagVal(CurrNode,"LastName"); PersonRec.Name=GetTagVal(CurrNode,"Name"); PersonRec.Phone=GetTagVal(CurrNode,"Phone"); PersonRec.Street=GetTagVal(CurrNode,"Street"); PersonRec.House=GetTagVal(CurrNode,"House"); PersonRec.App=GetTagVal(CurrNode,"App"); PersonRec.Note=GetTagVal(CurrNode,"Note"); //Сохраняем объект PersonRec в массиве PersonArr this.PersonArr[this.PersonArr.length]=PersonRec; } } //Запись данных из формы в XML-файл function ListPersons_SaveData() { var Root,CurrNode,ElemList; //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XML.documentElement; //Сохраняем в переменной CurrNode ссылку на (CurRecord+1)-й //элемент Person CurrNode=Root.childNodes.item(this.CurRecord+1); //Записываем данные из полей ввода формы в соответствующие //XML-элементы, которые являются дочерними узлами //относительно CurrNode SetTagVal(CurrNode,"LastName",doc.all.txtLastName.value); SetTagVal(CurrNode,"Name",doc.all.txtName.value); SetTagVal(CurrNode,"Phone",doc.all.txtPhone.value); SetTagVal(CurrNode,"Street",doc.all.txtStreet.value); SetTagVal(CurrNode,"House",doc.all.txtHouse.value); SetTagVal(CurrNode,"App",doc.all.txtApp.value); SetTagVal(CurrNode,"Note",doc.all.txtNote.value); //Сохраняем XML-файл на диске XML.save(PathBook); } //Загрузка данных для текущей записи в форму function ListPersons_LoadDialog() { //Вызываем метод LoadDialog для объекта Person, //который является CurRecord-м элементом массива PersonArr this.PersonArr[this.CurRecord].LoadDialog(); } //Обновление данных в форме function ListPersons_RefreshDialog(IsGoTop) { //Обнуляем массив PersonArr this.PersonArr.length=0; //Заново загружаем данные из XML-файла в массив PersonArr this.FileToArray(); if (IsGoTop) //Переходим к первой записи в массиве this.FirstRecord() else //Переходим к последней записи в массиве this.FinalRecord(); //Загружаем в форму данные для текущей записи this.LoadDialog(); } //Переход к следующей записи function ListPersons_NextRecord() { if (this.CurRecord<this.PersonArr.length - 1) //Если текущая запись не является последней, увеличиваем //номер текущей записи this.CurRecord++; } //Переход к предыдущей записи function ListPersons_PreviousRecord() { if (this.CurRecord > 0) //Если текущая запись не является первой, уменьшаем //номер текущей записи this.CurRecord--; } //Переход к первой записи function ListPersons_FirstRecord() { this.CurRecord = 0; } //Переход к последней записи function ListPersons_FinalRecord() { this.CurRecord = this.PersonArr.length - 1; } //Добавление новой записи function ListPersons_NewRecord() { var Root,NewElem; //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XML.documentElement; //Создаем новый элемент Person NewElem=XML.createElement("Person"); //Добавляем новый элемент в XML-файл Root.appendChild(NewElem); //Сохраняем XML-файл на диске XML.save(PathBook); //Обновлем в форме данные для последней добавленной записи this.RefreshDialog(false); } //Удаление текущей записи function ListPersons_DelRecord() { var Root,DelNom; //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XML.documentElement; //В переменной DelNom сохраняем номер удаляемого элемента Person DelNom=this.CurRecord+1; //Удаляем DelNom-й элемент Person из XML-файла Root.removeChild(Root.childNodes.item(DelNom)) //Сохраняем XML-файл на диске XML.save(PathBook); //Выводим сообщение о том, что запись удалена WshShell.Popup("Запись N "+DelNom+" удалена",0,"Информация", vbInformation+vbOkOnly); //Обновлем в форме данные для первой записи this.RefreshDialog(true); } Вывод формы из сценария WSH Для того чтобы вывести из сценария WSH разработанную HTML-форму на экран, нужно вначале получить ссылку на объект Application, который определяется в объектной модели Internet Explorer. Делается это следующим образом: var ie = WScript.CreateObject("InternetExplorer.Application", "ie_"); При этом в память загружается новый экземпляр Internet Explorer, а ссылка на этот объект присваивается переменной ie(само окно браузера по умолчанию невидимо, для его отображения на экране необходимо установить свойство Visibleобъекта Applicationв 1). В качестве второго параметра метода CreateObjectуказан префикс " ie_", посредством которого мы сможем написать функции-обработчики событий Internet Explorer. Внешний вид браузера Internet Explorer настраивается с помощью нескольких свойств объекта Application: //Устанавливаем свойства объекта ie для отображения формы ie.AddressBar = false; //Адресная строка не выводится ie.Fullscreen = false; //Полноэкранный режим запрещен ie.MenuBar = false; //Главное меню браузера не выводится ie.Resizable = false; //Изменять размеры окна нельзя ie.StatusBar = false; //Строка статуса не выводится ie.ToolBar = false; //Инструментальная панель не выводится //Устанавливаем размеры окна ie.Height = 300; //Высота ie.Width = 780; //Длина Для того чтобы загрузить в браузер нужный нам файл Phone.htm с описанием формы, используется метод Navigate объекта Application: ie.Navigate(PathHTML); В качестве параметра метода Navigateуказывается путь к файлу Phone.htm, который заранее устанавливается в функции InitPath(): function InitPath() { BasePath=WshShell.CurrentDirectory+"\\"; //Путь к файлу с данными PathBook=BasePath+"book.xml"; //Путь к файлу с HTML-формой PathHTML=BasePath+"Phone.htm"; } Далее следует учесть, что сценарий WSH и окно браузера, в котором загружена форма, — это два независимых процесса. Поэтому в сценарии после загрузки формы в окно браузера необходимо дождаться, пока пользователь не закроет это окно. Для этого мы присвоим глобальной переменной IsQuitзначение falseи заставим сценарий выполняться до тех пор, пока значение этой переменной не станет равным true: while (!IsQuit) //Приостанавливаем сценарий на 0,1 сек WScript.Sleep(100); При закрытии формы будет генерироваться событие OnQuitобъекта Application, поэтому мы напишем функцию-обработчик ie_OnQuit()этого события, в которой будем устанавливать isQuitв trueи сохранять в XML- файле данные, которые были изменены в форме (листинг 7.9). Листинг 7.9. Функция-обработчик закрытия окна браузера function ie_OnQuit() { IsQuit=true; //Сохраняем данные из формы в XML-файле objListPersons.SaveData(); } В нашем сценарии загрузка в браузер HTML-файла с формой будет производиться в основной запускной функции Main()(листинг 7.10). Листинг 7.10. Функция Main() function Main() { //Создаем объект WshShell WshShell = WScript.CreateObject("WScript.Shell"); //Определяем пути к файлам InitPath(); //Создаем объект InternetExplorer.Application с возможностью //обработки событий этого объекта ie = WScript.CreateObject("InternetExplorer.Application", "ie_"); //Устанавливаем свойства объекта ie для отображения формы3 ie.AddressBar = false; ie.FullScreen = false; ie.MenuBar = false; ie.Resizable = false; ie.StatusBar = false; ie.ToolBar = false; //Устанавливаем размеры окна ie.Height = 300; //Высота ie.Width = 780; //Длина IsQuit=false; //Загружаем HTML-файл с формой ie.Navigate(PathHTML); while (!IsQuit) //Приостанавливаем сценарий на 0,1 сек WScript.Sleep(100); } После окончания загрузки в браузер HTML-файла с формой нужно считать информацию из XML-файла с данными и отобразить в форме данные для первой записи. Мы будем это делать в функции-обработчике ie_DocumentComplete()события DocumentCompleteобъекта Application, которое генерируется как раз после окончания загрузки документа в браузер (листинг 7.11). Листинг 7.11. Функция-обработчик окончания загрузки документа в браузер function ie_DocumentComplete() { //Создаем экземпляр objListPersons объекта ListPersons objListPersons = new ListPersons(); //Загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); //Получаем ссылку на объект Document doc = ie.Document; //Устанавливаем заголовок окна doc.title = "Редактирование данных"; //Указываем функции-обработчики нажатий на кнопки формы doc.all.btnSave.onclick=btnSave_OnClick; doc.all.btnCancel.onclick=btnCancel_OnClick; doc.all.btnFirst.onclick=btnFirst_OnClick; doc.all.btnPrevious.onclick=btnPrevious_OnClick; doc.all.btnNew.onclick=btnNew_OnClick; doc.all.btnDelete.onclick=btnDelete_OnClick; doc.all.btnNext.onclick=btnNext_OnClick; doc.all.btnFinal.onclick=btnFinal_OnClick; //Указываем функции-обработчики изменения текста в полях ввода doc.all.txtLastName.onchange = txtBoxOnChange; doc.all.txtName.onchange = txtBoxOnChange; doc.all.txtPhone.onchange = txtBoxOnChange; doc.all.txtStreet.onchange = txtBoxOnChange; doc.all.txtHouse.onchange = txtBoxOnChange; doc.all.txtApp.onchange = txtBoxOnChange; doc.all.txtNote.onchange = txtBoxOnChange; if (objListPersons.PersonArr.length < 1) //Если в XML-файле нет данных, добавляем пустую запись objListPersons.AddRecord(); //В качестве текущей устанавливаем первую запись objListPersons.CurRecord = 0; //Загружаем в форму данные из массива PersonArr //для первой записи objListPersons.LoadDialog(); // Делаем окно Internet Explorer'а видимым ie.Visible = true; } В функции ie_DocumentComplete(), кроме прочего, задаются функции-обработчики событий, генерируемых в форме текстовыми полями ввода и кнопками. К описанию процесса обработки таких событий мы и перейдем. Обработка событий, генерируемых элементами управления формы В нашем сценарии мы будем обрабатывать события, связанные с нажатием на кнопки в форме и с изменением текста в полях ввода. Для этого нужно, во-первых, получить ссылку на соответствующий элемент управления в форме, зная его имя, которое задается атрибутом name в HTML-файле, например: <input type="button" value="<<" name="btnFirst"> Для доступа к элементу управления используется объект Document, который соответствует загруженному в браузер HTML-документу. Ссылка на объект Document Хранится в свойстве Document объекта Application: //Получаем ссылку на объект Document doc = ie.Document; Обработчики событий для элементов управления формы указываются тогда следующим образом: doc.all.ControlName.EventName=FunctionName; Здесь onclick, а событие, происходящее при изменении текста в поле ввода, — onchange: //Указываем функции-обработчики нажатий на кнопки формы doc.all.btnSave.onclick=btnSave_OnClick; doc.all.btnCancel.onclick=btnCancel_OnClick; doc.all.btnFirst.onclick=btnFirst_OnClick; doc.all.btnPrevious.onclick=btnPrevious_OnClick; doc.all.btnNew.onclick=btnNew_OnClick; doc.all.btnDelete.onclick=btnDelete_OnClick; doc.all.btnNext.onclick=btnNext_OnClick; doc.all.btnFinal.onclick=btnFinal_OnClick; //Указываем функции-обработчики изменения текста в полях ввода doc.all.txtLastName.onchange = txtBoxOnChange; doc.all.txtName.onchange = txtBoxOnChange; doc.all.txtPhone.onchange = txtBoxOnChange; doc.all.txtStreet.onchange = txtBoxOnChange; doc.all.txtHouse.onchange = txtBoxOnChange; doc.all.txtApp.onchange = txtBoxOnChange; doc.all.txtNote.onchange = txtBoxOnChange; Сами функции-обработчики нажатий на различные кнопки и изменения текста в полях ввода приведены с подробными комментариями в листинге 7.12. Листинг 7.12. Функции-обработчики нажатия кнопок и изменения поло ввода//Функция-обработчик нажатия на кнопку "Сохранить" function btnSave_OnClick() { //Сохраняем данные из формы в XML-файле objListPersons.SaveData(); } //Функция-обработчик нажатия на кнопку "Отменить" function btnCancel_OnClick() { //Заново загружаем данные из текущего элемента массива //в форму objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Данные восстановлены"; } //Функция-обработчик нажатия на кнопку "<<" function btnFirst_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Переходим к первой записи в массиве objListPersons.FirstRecord(); //Загружаем в форму данные из массива PersonArr //для первой записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись N " + (objListPersons.CurRecord + 1); } //Функция-обработчик нажатия на кнопку "<" function btnPrevious_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Переходим к предыдущей записи в массиве objListPersons.PreviousRecord(); //Загружаем в форму данные из массива PersonArr //для текущей записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись N " + (objListPersons.CurRecord + 1); } //Функция-обработчик нажатия на кнопку "Новая запись" function btnNew_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Добавляем новую запись в XML-файл objListPersons.NewRecord(); //Загружаем в форму данные из массива PersonArr //для добавленной записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Добавлена новая запись"; } //Функция-обработчик нажатия на кнопку "Удалить" function btnDelete_OnClick() { //Удаляем текущую запись из XML-файла objListPersons.DelRecord(); //Загружаем в форму данные из массива PersonArr //для первой записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись удалена"; } //Функция-обработчик нажатия на кнопку ">" function btnNext_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Переходим к следующей записи в массиве objListPersons.NextRecord(); //Загружаем в форму данные из массива PersonArr //для текущей записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись N " + (objListPersons.CurRecord + 1); } //Функция-обработчик нажатия на кнопку ">>" function btnFinal_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Переходим к последней записи в массиве objListPersons.FinalRecord(); //Загружаем в форму данные из массива PersonArr //для текущей записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись N " + (objListPersons.CurRecord + 1); } //Функция-обработчик изменения текста в полях ввода function txtBoxOnChange() { //Устанавливаем признак изменения данных в форме objListPersons.IsChanged = true; //Выводим сообщение в заголовке окна doc.title = "Редактирование данных"; } Окончательная доработка сценария IEPhoneBook.js Выше были описаны все основные функции, которые используются для работы с записной книжкой в диалоговом режиме. Осталось лишь собрать эти функции в один JScript-сценарий IEPhoneBook.js, определить глобальные переменные и добавить вспомогательные функции GetTagVal(obj, tgName)и SetTagVal(obj, tgName, sVal)для доступа к значениям XML-элементов (листинг 7.13). Листинг 7.13. Функция для доступа к значениям XML-элементов //Определение значения тега tgName XML-элемента obj function GetTagVal(obj, tgName) { var ElemList; //Создаем коллекцию дочерних для obj элементов, которые //задаются тегом tgName ElemList=obj.getElementsByTagName(tgName); //Проверяем, есть ли в коллекции ElemList элементы if (ElemList.length>0) //Возвращаем значение тега tgName return ElemList.item(0).text else return ""; } //Изменение значения тега tgName XML-элемента obj function SetTagVal(obj, tgName, sVal) { var ElemList,New; //Создаем коллекцию дочерних для obj элементов, которые //задаются тегом tgName ElemList=obj.getElementsByTagName(tgName); //Проверяем, есть ли в коллекции ElemList элементы if (ElemList.length>0) //Устанавливаем значение элемента, задаваемого //тегом tgName ElemList.item(0).text=sVal; else { //Создаем новый элемент с именем tgName NewElem=XML.createElement(tgName); //Добавляем новый элемент в качестве дочернего для //элемента obj obj.appendChild(NewElem); //Устанавливаем значение добавленного элемента obj.lastChild.text=sVal; } } Полный текст сценария IEPhoneBook.js приведен в листинге 7.14. Листинг 7.14. Сценарий IEPhoneBook.js/*******************************************************************/ /* Имя: IEPhoneBook.js */ /* Язык: JScript */ /* Описание: Сценарий для работы с записной книжкой */ /* (графический интерфейс пользователя на основе */ /* HTML-формы). */ /*******************************************************************/ //Объявляем глобальные переменные var WshShell, PathBook, //Путь к файлу с данными PathHTML, //Путь к HTML-файлу с формой XML, //Экземпляр объекта XML DOM ie, //Экземпляр объекта InternetExplorer.Application doc, //Экземпляр объекта Document IsQuit, //Признак выхода из сценария objListPersons; //Экземпляр объекта ListPersons //Инициализируем константы для диалоговых окон var vbInformation=64,vbOkOnly=0; //Построение путей к файлам function InitPath() { BasePath=WshShell.CurrentDirectory+"\\"; //Путь к файлу с данными PathBook=BasePath+"book.xml"; //Путь к файлу с HTML-формой PathHTML=BasePath+"Phone.htm"; } //Определение значения тега tgName XML-элемента obj function GetTagVal(obj, tgName) { var ElemList; //Создаем коллекцию дочерних для obj элементов, которые //задаются тегом tgName ElemList=obj.getElementsByTagName(tgName); //Проверяем, есть ли в коллекции ElemList элементы if (ElemList.length>0) //Возвращаем значение тега tgName return ElemList.item(0).text else return ""; } //Изменение значения тега tgName XML-элемента obj function SetTagVal(obj, tgName, sVal) { var ElemList,New; //Создаем коллекцию дочерних для obj элементов, которые //задаются тегом tgName ElemList=obj.getElementsByTagName(tgName); //Проверяем, есть ли в коллекции ElemList элементы if (ElemList.length>0) //Устанавливаем значениеэлемента, задаваемого //тегом tgName ElemList.item(0).text=sVal; else { //Создаем новый элемент с именем tgName NewElem=XML.createElement(tgName); //Добавляем новый элемент в качестве дочернего для //элемента obj obj.appendChild(NewElem); //Устанавливаем значение добавленного элемента obj.lastChild.text=sVal; } } //Конструктор объекта Person function Person() { //Инициализируем свойства объекта this.LastName=""; this.Name=""; this.Phone=""; this.Street=""; this.House=""; this.App=""; this.Note=""; //Устанавливаем для метода LoadDialog указатель на //функцию Person_LoadDialog this.LoadDialog=Person_LoadDialog; } //Заполнение полей в форме для текущей записи function Person_LoadDialog() { //Заполняем поля ввода в форме значениями соответствующих //свойств объекта Person doc.all.txtLastName.value = this.LastName; doc.all.txtName.value=this.Name; doc.all.txtPhone.value=this.Phone; doc.all.txtStreet.value=this.Street; doc.all.txtHouse.value=this.House; doc.all.txtApp.value = this.App; doc.all.txtNote.value = this.Note; } //Конструктор объекта ListPersons function ListPersons() { // Свойства объекта //Создаем массив PersonArr экземпляров объекта Person this.PersonArr = new Array(); //Инициализируем номер текущей записи this.CurRecord = 0; //Сбрасываем признак изменения данных в форме this.IsChanged = false; // Методы объекта //Устанавливаем для методов указатели на соответствующие функции this.FileToArray=ListPersons_FileToArray; this.SaveData=ListPersons_SaveData; this.LoadDialog=ListPersons_LoadDialog; this.RefreshDialog=ListPersons_RefreshDialog; this.NextRecord=ListPersons_NextRecord; this.PreviousRecord=ListPersons_PreviousRecord; this.FirstRecord=ListPersons_FirstRecord; this.FinalRecord=ListPersons_FinalRecord; this.NewRecord=ListPersons_NewRecord; this.DelRecord = ListPersons_DelRecord; } //Считывание данных из XML-файла в массив объектов Person function ListPersons_FileToArray() { var Root,CurrNode,i; //Создаем объект XML DOM XML = WScript.CreateObject("Msxml.DOMDocument"); //Загружаем XML-документ из файла XML.load(PathBook); //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XML.documentElement; //Обнуляем массив PersonArr this.PersonArr.length=0; //Перебираем все дочерние элементы первого уровня вложенности //для корневого элемента for (i=1; i<=Root.childNodes.length-1;i++) { //Выделяем в коллекции XML-элементов i-й элемент CurrNode=Root.childNodes.item(i); //Создаем новый экземпляр PersonRec объекта Person PersonRec=new Person(); //Заполняем поля объекта PersonRec PersonRec.LastName=GetTagVal(CurrNode,"LastName"); PersonRec.Name=GetTagVal(CurrNode,"Name"); PersonRec.Phone=GetTagVal(CurrNode,"Phone"); PersonRec.Street=GetTagVal(CurrNode,"Street"); PersonRec.House=GetTagVal(CurrNode,"House"); PersonRec.App=GetTagVal(CurrNode,"App"); PersonRec.Note=GetTagVal(CurrNode,"Note"); //Сохраняем объект PersonRec в массиве PersonArr this.PersonArr[this.PersonArr.length]=PersonRec; } } //Запись данных из формы в XML-файл function ListPersons_SaveData() { var Root,CurrNode,ElemList; //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XML.documentElement; //Сохраняем в переменной CurrNode ссылку на (CurRecord+1)-й //элемент Person CurrNode=Root.childNodes.item(this.CurRecord+1); //Записываем данные из полей ввода формы в соответствующие //XML-элементы, которые являются дочерними узлами //относительно CurrNode SetTagVal(CurrNode,"LastName",doc.all.txtLastName.value); SetTagVal(CurrNode,"Name",doc.all.txtName.value); SetTagVal(CurrNode,"Phone",doc.all.txtPhone.value); SetTagVal(CurrNode,"Street",doc.all.txtStreet.value); SetTagVal(CurrNode,"House",doc.all.txtHouse.value); SetTagVal(CurrNode,"App",doc.all.txtApp.value); SetTagVal(CurrNode,"Note",doc.all.txtNote.value); //Сохраняем XML-файл на диске XML.save(PathBook); } //Загрузка данных для текущей записи в форму function ListPersons_LoadDialog() { //Вызываем метод LoadDialog для объекта Person, //который является CurRecord-м элементом массива PersonArr this.PersonArr[this.CurRecord].LoadDialog(); } //Обновление данных в форме function ListPersons_RefreshDialog(IsGoTop) { //Обнуляем массив PersonArr this.PersonArr.length=0; //Заново загружаем данные из XML-файла в массив PersonArr this.FileToArray(); if (IsGoTop) //Переходим к первой записи в массиве this.FirstRecord() else //Переходим к последней записи в массиве this.FinalRecord(); //Загружаем в форму данные для текущей записи this.LoadDialog(); } //Переход к следующей записи function ListPersons_NextRecord() { if (this.CurRecord<this.PersonArr.length - 1) //Если текущая запись не является последней, увеличиваем //номер текущей записи this.CurRecord++; } //Переход к предыдущей записи function ListPersons_PreviousRecord() { if (this.CurRecord > 0) //Если текущая запись не является первой, уменьшаем //номер текущей записи this.CurRecord--; } //Переход к первой записи function ListPersons_FirstRecord() { this.CurRecord = 0; } //Переход к последней записи function ListPersons_FinalRecord() { this.CurRecord = this.PersonArr.length - 1; } //Добавление новой записи function ListPersons_NewRecord() { var Root,NewElem; //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XML.documentElement; //Создаем новый элемент Person NewElem=XML.createElement("Person"); //Добавляем новый элемент в XML-файл Root.appendChild(NewElem); //Сохраняем XML-файл на диске XML.save(PathBook); //Обновлем в форме данные для последней добавленной записи this.RefreshDialog(false); } //Удаление текущей записи function ListPersons_DelRecord() { var Root,DelNom; //Сохраняем в переменной Root ссылку на корневой элемент //документа Root=XML.documentElement; //В переменной DelNom сохраняем номер удаляемого элемента Person DelNom=this.CurRecord+1; //Удаляем DelNom-й элемент Person из XML-файла Root.removeChild(Root.childNodes.item(DelNom)) //Сохраняем XML-файл на диске XML.save(PathBook); //Выводим сообщение о том, что запись удалена WshShell.Popup("Запись N "+DelNom+" удалена",0,"Информация", vbInformation+vbOkOnly); //Обновлем в форме данные для первой записи this.RefreshDialog(true); } // Обработчики событий Internet Explorer'a //Функция-обработчик окончания загрузки документа в Internet Explorer function ie_DocumentComplete() { //Создаем экземпляр objListPersons объекта ListPersons objListPersons = new ListPersons(); //Загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); //Получаем ссылку на объект Document doc = ie.Document; //Устанавливаем заголовок окна doc.title = "Редактирование данных"; //Указываем функции-обработчики нажатий на кнопки формы doc.all.btnSave.onclick=btnSave_OnClick; doc.all.btnCancel.onclick=btnCancel_OnClick; doc.all.btnFirst.onclick=btnFirst_OnClick; doc.all.btnPrevious.onclick=btnPrevious_OnClick; doc.all.btnNew.onclick=btnNew_OnClick; doc.all.btnDelete.onclick=btnDelete_OnClick; doc.all.btnNext.onclick=btnNext_OnClick; doc.all.btnFinal.onclick=btnFinal_OnClick; //Указываем функции-обработчики изменения текста в полях ввода doc.all.txtLastName.onchange = txtBoxOnChange; doc.all.txtName.onchange = txtBoxOnChange; doc.all.txtPhone.onchange = txtBoxOnChange; doc.all.txtStreet.onchange = txtBoxOnChange; doc.all.txtHouse.onchange = txtBoxOnChange; doc.all.txtApp.onchange = txtBoxOnChange; doc.all.txtNote.onchange = txtBoxOnChange; if (objListPersons.PersonArr.length < 1) //Если в XML-файле нет данных, добавляем пустую запись objListPersons.AddRecord(); //В качестве текущей устанавливаем первую запись objListPersons.CurRecord = 0; //Загружаем в форму данные из массива PersonArr //для первой записи objListPersons.LoadDialog(); // Делаем окно Internet Explorer'а видимым ie.Visible = true; } //Функция-обработчик закрытия окна Internet Explorer'а function ie_OnQuit() { IsQuit=true; //Сохраняем данные из формы в XML-файле objListPersons.SaveData(); } // Обработчики нажатий на кнопки в форме //Функция-обработчик нажатия на кнопку "Сохранить" function btnSave_OnClick() { //Сохраняем данные из формы в XML-файле objListPersons.SaveData(); } //Функция-обработчик нажатия на кнопку "Отменить" function btnCancel_OnClick() { //Заново загружаем данные из текущего элемента массива //в форму objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Данные восстановлены"; } //Функция-обработчик нажатия на кнопку "<<" function btnFirst_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Переходим к первой записи в массиве objListPersons.FirstRecord(); //Загружаем в форму данные из массива PersonArr //для первой записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись N " + (objListPersons.CurRecord + 1); } //Функция-обработчик нажатия на кнопку "<" function btnPrevious_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Переходим к предыдущей записи в массиве objListPersons.PreviousRecord(); //Загружаем в форму данные из массива PersonArr //для текущей записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись N " + (objListPersons.CurRecord + 1); } //Функция-обработчик нажатия на кнопку "Новая запись" function btnNew_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Добавляем новую запись в XML-файл objListPersons.NewRecord(); //Загружаем в форму данные из массива PersonArr //для добавленной записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Добавлена новая запись"; } //Функция-обработчик нажатия на кнопку "Удалить" function btnDelete_OnClick() { //Удаляем текущую запись из XML-файла objListPersons.DelRecord(); //Загружаем в форму данные из массива PersonArr //для первой записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись удалена"; } //Функция-обработчик нажатия на кнопку ">" function btnNext_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Переходим к следующей записи в массиве objListPersons.NextRecord(); //Загружаем в форму данные из массива PersonArr //для текущей записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись N " + (objListPersons.CurRecord + 1); } //Функция-обработчик нажатия на кнопку ">>" function btnFinal_OnClick() { //Проверяем, были ли сделаны изменения в форме if (objListPersons.IsChanged) { //Изменения были сделаны //Сохраняем данные в XML-файле objListPersons.SaveData(); //Заново загружаем данные из XML-файла в массив PersonArr objListPersons.FileToArray(); } //Переходим к последней записи в массиве objListPersons.FinalRecord(); //Загружаем в форму данные из массива PersonArr //для текущей записи objListPersons.LoadDialog(); //Выводим сообщение в заголовке окна doc.title = "Запись N " + (objListPersons.CurRecord + 1); } //Функция-обработчик изменения текста в полях ввода function txtBoxOnChange() { //Устанавливаем признак изменения данных в форме objListPersons.IsChanged = true; //Выводим сообщение в заголовке окна doc.title = "Редактирование данных"; } //Основная запускная функция function Main() { //Создаем объект WshShell WshShell = WScript.CreateObject("WScript.Shell"); //Определяем пути к файлам InitPath(); //Создаем объект InternetExplorer.Application с возможностью //обработки событий этого объекта ie = WScript.CreateObject("InternetExplorer.Application", "ie_"); //Устанавливаем свойства объекта ie для отображения формы3 ie.AddressBar = false; ie.FullScreen = false; ie.MenuBar = false; ie.Resizable = false; ie.StatusBar = false; ie.ToolBar = false; //Устанавливаем размеры окна ie.Height = 300; //Высота ie.Width = 780; //Длина IsQuit=false; //Загружаем HTML-файл с формой ie.Navigate(PathHTML); while (!IsQuit) //Приостанавливаем сценарий на 0,1 сек WScript.Sleep(100); } /******************* Начало **********************************/ Main(); /************* Конец *********************************************/ |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Главная | Контакты | Нашёл ошибку | Прислать материал | Добавить в избранное |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|