Базы данныхИнтернетКомпьютерыОперационные системыПрограммированиеСетиСвязьРазное
Поиск по сайту:
Подпишись на рассылку:

Назад в раздел

Как создавать DHTML из списков Microsoft Office

div.main {margin-left: 20pt; margin-right: 20pt} Как создавать DHTML из списков Microsoft Office

Виталий Сизов
программист, специалист по разработке на платформе Microsoft Office для Web (Visual Basic for Applications, JavaScript),
sva@hot.ee Постановка задачи

Развитие Интернета все больше привлекает внимание коммерческих организаций, желающих представить миру собственные коллекции товаров и услуг в виде электронных магазинов, прейскурантов, спецификаций. В большинстве случаев начинающие электронную коммерцию предприятия не имеют корпоративных Web-серверов, и у них нет специалистов, способных реализовать базы данных SQL и технологии клиент-сервер. Все, чем располагает "обычная" компания, - это документы Microsoft Office (таблицы Excel, базы данных Access и тексты Word). Домашние страницы таких компаний размещаются чаще всего на бесплатных серверах, с ограниченным набором возможностей.

Но оказывается, всего этого вполне достаточно, чтобы реализовать если уж не магазин, то вполне приличный электронный ларек. Не потребуется даже мощный редактор HTML, от которого просто не будет проку, поскольку страницы со списком товаров должны формироваться динамически. Все, что действительно необходимо, - это исходные данные в виде списка, Visual Basic for Applications, JavaScript, CSS и текстовый редактор Notepad.

Для большей конкретности формализуем задачу. Пусть для нашего электронного ларька требуется список товаров со следующими реквизитами: код, наименование, единица измерения и цена. Список должен быть разбит на разделы, соответствующие товарным группам. Для некоторых товаров желательно предусмотреть подробное описание в виде полноценной Web-страницы, для других товаров достаточно небольшой картинки с кратким комментарием. Таким образом, получим следующую структуру записи базы данных:

Идентификатор

НазначениеКомментарий

code

Код или номенклатурный номер Число или строка, служащие для идентификации товара по каталогу продавца и безразличные для покупателя

name

Наименование товара Cтрока

home

Домашняя страница товара Ссылка на страницу с подробным описанием в виде полного или неполного URL

unit

Единица измерения Строка (для штучных товаров обычно не заполняется)

price

Цена единицы Число
comment Краткое описание Строка, возможно, содержащая HTML-тэги

Создав структуру базы данных, следует ее реализовать и заполнить теми данными, которые содержатся в имеющихся документах Microsoft Office. Лучше всего для этой цели подходит рабочая таблица Excel. Создание коллекции объектов

После того, как база данных некоторым образом подготовлена, можно приступить к созданию HTML-кода страницы. Используем простую заготовку.
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset= windows-1251"> <title>Электронный магазин</title> <style TYPE="text/css"> <!-- //-- Здесь будет таблица стилей --> </style> <script> <!-- hide this script from non-JavaScript browsers n = (document.layers) ? 1:0 ie = (document.all) ? 1:0 //-- Здесь будет Script // done hiding from old browsers --> </script> </head> <body> //-- Здесь будет тело документа </body> </html>

В разделе HEAD приступим к составлению скрипта (см. место Script в коде-заготовке). Для начала позаботимся о разумном представлении базы данных. Создадим полноценную коллекцию объектов goods (товары). Каждый экземпляр из этой коллекции будет иметь свойства, одноименные определенным выше реквизитам. Дополнительно нам пригодятся еще два свойства: len (счетчик экземпляров) и maxlen (максимально допустимое количество экземпляров в коллекции). Свойство maxlen не обязательно, но если нужно ограничить размер загружаемой базы данных, его можно использовать в методе Add. Создание коллекции неограниченного размера выполняется следующим образом:

var MAX_ITEM = 1 function MakeArray(n) { for (var i = 1; i <= n; i++) { this[i] = 0 } this.maxlen = n this.len = 0 return this } var goods = MakeArray(MAX_ITEM) function Item(code, name, home, unit, price, comment) { this.code = code this.name = name this.home = home this.unit = unit this.price = price this.comment = comment }

Для добавления экземпляров в коллекцию goods понадобится единственный метод (функция) Add:

function Add(code, name, home, unit, price, comment) { goods.len++ goods[goods.len] = new Item(code, name, home, unit, price, comment) }

Использование метода Add

Поскольку коллекция объектов создана, наша страница готова к приему информации. Для каждой записи исходной базы данных необходимо выполнить метод Add. На языке JavaScript это должно выглядеть следующим образом:

Add(code1, "name1", "home1", "unit1", price1, "comment1") Add(code2, "name2", "home2", "unit2", price2, "comment2") Add(code3, "name3", "home3", "unit3", price3, "comment3") . . . . . . . . . Add(codeI, "nameI", "homeI", "unitI", priceI, "commentI") . . . . . . . . . Add(codeN, "nameN", "homeN", "unitN", priceN, "commentN")

В скобках здесь стоят конкретные значения, извлекаемые из исходной таблицы Excel, содержащей N записей. Следует обратить внимание, что строковые данные заключаются в кавычки, а для числовых кавычки не обязательны. Другими словами, вся премудрость загрузки базы данных заключается в преобразовании исходной таблицы в текстовый файл, строки которого начинаются со слова Add, далее в круглых скобках следуют реквизиты, разделенные запятыми. Отсутствующий реквизит нужно представить в виде (""). Избыточность в данном случае очень незначительна. Текстовый файл приемлемой для Web длины (200-300 Кбайт) позволяет записать несколько тысяч наименований.

Конечно, файл, представляющий базу данных в такой экзотической форме, должен существовать самостоятельно. Для его подключения к HTML-странице потребуется описание (подразумевается, что имя файла базы данных - list.js):

Эти строки следует поместить также в разделе HEAD, желательно ниже основного скрипта, помещенного на место Script, чтобы многократные вызовы метода Add следовали после описания самой функции. Теперь любой браузер, открыв страницу, загрузит и объемную базу данных. Группировка записей

При постановке задачи мы уже отмечали, что данные необходимо группировать. Самая современная и эффектная форма группирования информации на HTML-странице - это nuggets (самородки), или, в современной терминологии, - Web Parts. Nugget - это внедренное в страницу окно, которое может открываться и сворачиваться. Заголовок nugget - это часто гиперссылка на домашнюю страницу группы. Технически реализовать nugget несложно; эта конструкция состоит из двух частей - заголовка и тела. Заголовок может быть представлен единственной строкой таблицы с двумя ячейками. В первой ячейке расположено наименование окна, а во второй - кнопка, вызывающая развертывание и свертывание тела.

Тело nugget - это именованный контейнер . Содержимое контейнера может быть произвольным, но в нашем случае это должна быть таблица. Оформление nugget обычно задается с помощью классов, объявленных в таблице стилей:

<table cellpadding="0" border="0" cellspacing="0" class="nuggetHeader"> <tr> <td nowrap width="100%" class="nuggetTitle" valign="center"> <a href="nugget.htm" class="nuggetTitleText">Nugget Title</a></td> <td nowrap class="nuggetButtonWrapper"> <img id="nToggle" src=" 2376/blank.gif" title="Click to maximize / minimize" onClick="document.all.nContent.style.display= _ document.all.nContent.style.display=='none'?'':'none'; _ if(document.images)this.src= _ document.all.nContent.style.display=='none'?imgMax.src: imgMin.src;" WIDTH="17" HEIGHT="17"></td> </tr> </table> <div valign="top" id="nContent"> <table width="100%" border="0" cellpadding="0" cellspacing="0" class="nuggetBody"> <tr> <td>Nugget Body</td> </tr> </table> </div>

Представленный выше фрагмент - лишь пример оформления nuggets; копировать и вставлять его в текст создаваемого DHTML-документа не потребуется.

Для формирования nugget достаточно задать имя и гиперссылку на домашнюю страницу группы. Для этой цели вполне подходят имеющиеся реквизиты name и home. Чтобы распознать во входном потоке заголовки разделов, достаточно зарезервировать специальные значения поля code. Например, если в поле code текущей записи стоит значение "пусто", то эту запись следует рассматривать в качестве заголовка нового раздела. Естественно, поля unit, price и comment придется в этом случае проигнорировать.

Таким образом, алгоритм обработки загруженной коллекции goods сводится к следующему. Для каждого экземпляра goods анализируется свойство code. Если code имеет значение "пусто", то нужно сформировать заголовок nugget с именем name и гиперссылкой home и начать новую таблицу. В противном случае - сформировать обычную строку текущей таблицы.

К сожалению, элегантная конструкция раскрывающегося окна будет работать только в Internet Explorer. Netscape Communicator не имеет объекта style и свойства display, и в нем описанная выше конструкция будет выглядеть статичной. Окно nugget будет постоянно раскрытым, а кнопка Maximize / Minimize окажется бесполезной. Чтобы не вводить в заблуждение пользователя, эта кнопка инициализируется "пустым" значением (src=" 2376/blank.gif").

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

Поскольку все подготовительные операции выполнены, приступим к динамическому отображению загруженной базы данных. Делается это с помощью функции DisplayList. Перед описанием функции необходимо проинициализировать глобальную переменную n_count, которая служит счетчиком nuggets и может использоваться при выборе стилей оформления.

var n_count = 0 function DisplayList() { for (i = 1; i <= goods.len; i++) { if ((goods[i].code == "") || (i == 1)) { if (n_count > 0) { document.writeln("</table>") document.writeln("</td>") document.writeln("</tr>") document.writeln("</table>") document.writeln("</div>") } n_count++ document.writeln("<table cellpadding="0" border="0" cellspacing="0" class="nuggetHeader">") document.writeln("<tr>") document.writeln("<td nowrap width="100%" class="nuggetTitle" valign="center">") document.writeln(" ") if (goods[i].home != "") { document.writeln("<a target="_blank" href="" + goods[i].home + "" class="nuggetTitleText">" + goods[i].name + "</a>") } else { document.writeln("<span class="nuggetTitleText">" + goods[i].name + "</span>") } document.writeln(" ") document.writeln("</td>") document.writeln("<td nowrap class="nuggetButtonWrapper">") document.writeln("<img id="nToggle" + n_count + "" src="images/blank.gif" title="Click to maximize / minimize" onClick=<BR>"document.all.nContent" + n_count + ".style.display=document.all.nContent" + n_count + ".style.display=='none'?'':'none';if(document.images) this.src=document.all.nContent" + n_count + ".style.display=='none'?imgMax.src:imgMin.src;" WIDTH="17" HEIGHT="17">") document.writeln("</td>") document.writeln("</tr>") document.writeln("</table>") document.writeln("<div valign="top" id="nContent" + n_count + "">") if (n_count%2 == 0) { document.writeln("<table width="100%" border="0" cellpadding="5" cellspacing="0" class="nuggetBodyEven">") } else { document.writeln("<table width="100%" border="0" cellpadding="5" cellspacing="0" class="nuggetBodyOdd">") } document.writeln("<tr>") document.writeln("<td>") document.writeln("<table>") } else { if (i%2 == 0) { document.writeln("<tr class="lineEven">") } else { document.writeln("<tr class="lineOdd">") } if (goods[i].home != "") { document.writeln("<td><a target="_blank" href="" + goods[i].home + "">" + goods[i].name + "</a></td>") } else { document.writeln("<td>" + goods[i].name + "</td>") } document.writeln("<td>" + goods[i].unit + "</td>") document.writeln("<td>" + goods[i].price + "</td>") document.writeln("<td><a href="javascript:void(0)" onClick="BasketInsert(" + i +")">Add</a></td>") document.writeln("</tr>") if (goods[i].comment != "") { document.writeln("<tr>") document.writeln("<td colspan="4">" + goods[i].comment + "</td>") document.writeln("</tr>") } } } document.writeln("</table>") document.writeln("</td>") document.writeln("</tr>") document.writeln("</table>") document.writeln("</div>") }

В приведенной выше процедуре используется набор стилей, предусматривающий разное оформление четных и нечетных строк, а также четных и нечетных nuggets. Описание стилей следует добавить в раздел HEAD в предусмотренном для этого месте, а еще лучше создать отдельный файл MyStyle.css и поместить в

Большинство стилей, которые могут потребоваться, приведены ниже:

<style TYPE="text/css"> <!-- a { font-family: Tahoma; color: #11057E; text-decoration: none; font-weight: bold; } a:link { font-family: Tahoma; color: #11057E; text-decoration: none; font-weight: bold; } a:hover { color: #ff0000; } p { font-family: Tahoma; font-size: 8pt; } td { font-family: Tahoma; font-size: 8pt; } .nuggetHeader { background-color: steelblue; } .nuggetTitle { cursor: default; border: 2px groove lightsteelblue; background-color: steelblue; width: 100%; } .nuggetTitleText { color: white; font-size: 10pt; font-weight: bold; font-family: Arial; } .nuggetButtonWrapper { cursor: hand; border: 2px groove lightsteelblue; background-color: steelblue; vertical-align: middle; } .nuggetBody { background-color: white; } .nuggetBodyOdd { background-color: white; } .nuggetBodyEven { background-color: ghostwhite; } a.nuggetTitleText { color: white; font-size: 10pt; font-weight: bold; font-family: Arial; } a.nuggetTitleText:active { color: yellow; font-size: 10pt; } .lineEven { background-color: pink; } .lineOdd { background-color: gold; } --> </style>

Заключительные конструкции

Все, что осталось сделать, - это разместить вызов функции DisplayList и решить вопрос о первоначальном состоянии nuggets - оставить их развернутыми или свернуть. Обычно nuggets сворачивают, чтобы пользователь мог охватить взглядом весь список товарных групп. Но можно один из nuggets оставить открытым, чтобы обратить особое внимание, например, на новинки коллекции. Поскольку все nuggets пронумерованы, сделать это не составляет труда. Не стоит забывать и о том, что в заголовках nuggets используются графические элементы. Для них надо предусмотреть операторы предварительной загрузки:

if(document.images){ imgMax = new Image(17,17) imgMax.src=" 2376/max.gif" imgMin = new Image(17,17) imgMin.src=" 2376/min.gif" imgBlank = new Image(17,17) imgBlank.src=" 2376/blank.gif" }

Операторы для начального свертывания nuggets помещают в функцию init(), которая завершает Script в заголовке страницы. Как уже говорилось выше, nuggets не предназначены для Netscape Communicator, поэтому функция init() выглядит следующим образом:

function init() { if (ie) { for (i = 1; i <= n_count; i++) { document.all["nContent" + i].style.display = "none" if (document.images) { document.images["nToggle" + i].src=imgMax.src } } } }

Вызов функции init выполняется в тэге :

Ну вот, наконец настало время для Web-дизайна. Только теперь мы добрались до тела страницы и можем продемонстрировать утонченный вкус. К сожалению, все, что нам осталось сделать в разделе BODY, - это поместить единственный оператор:

<script> <!-- DisplayList() //--> </script>

Работа закончена. Конечно, можно украсить страницу логотипом фирмы, панелью навигации и другими "погремушками и свистульками", но все это уже выходит за рамки поставленной задачи.

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

. Поэтому, если поместить вызов DisplayList внутрь таблицы, то пользователь очень долго будет наблюдать пустой экран, ожидая, пока ВСЕ nuggets динамически сформируются.

На рис. 1. показан вид описанной DHTML-страницы, открытой в Internet Explorer. Дополнительно реализованы правые и левые margin и к каждой строке добавлена ссылка Add, позволяющая помещать товары в "покупательскую корзину". Один из nuggets распахнут, остальные свернуты.

Экспорт списков

Черновая работа по редактированию и загрузке базы данных, как всегда, остается на долю Microsoft Office. В описываемом примере источник информации размещается на странице Microsoft Excel.

Не будем останавливаться на операциях редактирования списка, они хорошо известны. Не станем затрагивать и выгрузку с помощью FTP, на эту тему имеются отдельные публикации. Главное внимание сосредоточим на макросе Export. Здесь следует учесть различия в представлении данных в Microsoft Office и JavaScript и предусмотреть коррекцию возможных ошибок пользователя.

Во-первых, необходимо помнить, что разделителем целой и дробной части чисел в JavaScript служит только точка. Во вторых, число 0 в JavaScript воспринимается и как пустая строка (""). В третьих, символы перевода строки и возврата каретки в строках JavaScript недопустимы. И, наконец, если нужно поместить в строковое выражение двойную кавычку, это делается в виде ("). С учетом этих замечаний макрос Export выглядит следующим образом:

Sub Export() '-- Формирование .JS файла Dim strFileName As Variant '-- Имя файла Dim objArea As Range '-- Смежная область Dim objDown As Range '-- Область без заголовков Dim objCurrCell As Range '-- Текущая ячейка Dim objCell As Range '-- Рабочая ячейка Dim strCode As String '-- Реквизит CODE Dim strName As String '-- Реквизит NAME Dim strHome As String '-- Реквизит HOME Dim strUnit As String '-- Реквизит UNIT Dim strPrice As String '-- Реквизит PRICE Dim strComment As String '-- Реквизит COMMENT Dim strLine As String '-- Строка вывода Dim intComaPos As Integer '-- Позиция запятой strFileName = ActiveWorkbook.Path & "" & FILE_NAME Open strFileName For Output As #1 '-- Открывает файл. Set objCurrCell = ActiveCell Range("A4").Activate Set objArea = ActiveCell.CurrentRegion Set objDown = objArea.Offset(1, 0).Resize(objArea.Rows.Count - 1, 1) For Each objCell In objDown objCell.EntireRow.Select '-- Извлечение с заменой двойных кавычек strCode = Selection.Range("B1").Value strName = CheckString(Selection.Range("C1").Value) strHome = CheckString(Selection.Range("D1").Value) strUnit = CheckString(Selection.Range("E1").Value) strPrice = Selection.Range("F1").Value strComment = CheckString(Selection.Range("G1").Value) '-- Коррекция строк заголовков If Selection.Range("B1").Font.Bold Then strCode = "" strUnit = "" strPrice = "" strComment = "" Else If strCode = "" Then strCode = "?" End If End If '-- Начало выходной строки strLine = "Add(" '-- Code: может быть и числом, и строкой If IsNumeric(strCode) And strCode <> "0" Then intComaPos = InStr(strCode, ",") If intComaPos > 0 Then strCode = Left(strCode, intComaPos - 1) & "." & _ Mid(strCode, intComaPos + 1) End If strLine = strLine & strCode & "," Else strLine = strLine & """" & CheckString(strCode) & """," End If '-- Name, Home и Unit: символьные строки strLine = strLine & """" & strName & """,""" & _ strHome & """,""" & strUnit & """," '-- Price: может быть и числом, и строкой If IsNumeric(strPrice) Then intComaPos = InStr(strPrice, ",") If intComaPos > 0 Then strPrice = Left(strPrice, intComaPos - 1) & "." & _ Mid(strPrice, intComaPos + 1) End If strLine = strLine & strPrice & "," Else strLine = strLine & """" & CheckString(strPrice) & """," End If '-- Comment: символьная строка strLine = strLine & """" & strComment & """)" '-- Вывод результата Print #1, strLine Next objCurrCell.Activate ActiveCell.Select Close #1 '-- Закрывает файл. MsgBox "File " & strFileName & " Brewed", vbInformation End Sub

Функция CheckString проверяет символьные строки на наличие двойных кавычек и управляющих символов и заменяет их допустимыми значениями:

Private Function CheckString(strIn) As String '-- Коррекция символьных строк Dim strLeft As String Dim strRight As String Dim intPos As Integer '-- Замена (") на пару (") strRight = strIn strLeft = "" intPos = InStr(strRight, """") Do While intPos > 0 strLeft = strLeft & Left(strRight, intPos - 1) & """" strRight = Mid(strRight, intPos + 1) intPos = InStr(strRight, """") Loop '-- Замена chr(10) на <br> strRight = strLeft & strRight strLeft = "" intPos = InStr(strRight, Chr(10)) Do While intPos > 0 strLeft = strLeft & Left(strRight, intPos - 1) & "<br>" strRight = Mid(strRight, intPos + 1) intPos = InStr(strRight, Chr(10)) Loop '-- Замена chr(13) на <br> strRight = strLeft & strRight strLeft = "" intPos = InStr(strRight, Chr(13)) Do While intPos > 0 strLeft = strLeft & Left(strRight, intPos - 1) & "<br>" strRight = Mid(strRight, intPos + 1) intPos = InStr(strRight, Chr(13)) Loop CheckString = strLeft & strRight End Function

В приведенном примере кода подразумевается, что имя выходного файла задано и не будет изменяться с помощью метода Application.GetSaveAsFilename. На практике дело обстоит именно так. Следующая за экспортом процедура выгрузки и сама DHTML-страница, как правило, уже настроены на конкретные имена файлов. Последние замечания

Динамика работы с приведенными конструкциями основана на регулярном обновлении текстового файла list.js, содержащего базу данных товаров. Владельцы информации обновляют список с помощью пакета Excel и выгружают его на сервер. Клиенты при открытии Web-страницы или выполнении команды Refresh всегда получают данные в актуальном состоянии. Все было бы прекрасно, если бы не медлительность браузеров при интерпретации команд write. Сама операция загрузки данных в коллекцию goods выполняется достаточно быстро, а вот процедура DisplayList - медленно. Особенно "тормозит" здесь Netscape Communicator, обычно славящийся высоким быстродействием, но это верно только в отношении "простых" HTML-страниц. Поэтому, несмотря на компактность файлов, позволяющих хранить и быстро загружать тысячи строк, их отображение браузером клиента может происходить недопустимо долго. И это несмотря на то, что все файлы загружены и каналы связи освобождены. На практике приемлемое количество записей в списке не превышает нескольких сотен. Но даже в этом случае, чтобы занять клиента на время выполнения процедуры DisplayList, следует предусмотреть предупреждающие сообщения типа "подождите, идет загрузка...".

С другой стороны, создание коллекции объектов goods открывает простор для дальнейшего творчества. Поскольку каждая строка в динамической таблице имеет свой уникальный номер, легко реализовать типичные процедуры электронного магазина. В качестве "покупательской корзины" появляется коллекция объектов basket, экземпляры которой повторяют экземпляры goods, но имеют дополнительное свойство "количество". Появляется возможность копировать экземпляры goods в basket c помощью описанного метода Add. Заметьте, что все это выполняется на клиентской стороне, без обращения к серверу. Можно даже просто отключиться от Интернета и "набивать" корзину товарами в автономном режиме. Подключение к серверу потребуется только в самый последний момент, для фиксации факта совершения покупки.

Как и было обещано, электронный ларек может получиться замечательным.



  • Главная
  • Новости
  • Новинки
  • Скрипты
  • Форум
  • Ссылки
  • О сайте




  • Emanual.ru – это сайт, посвящённый всем значимым событиям в IT-индустрии: новейшие разработки, уникальные методы и горячие новости! Тонны информации, полезной как для обычных пользователей, так и для самых продвинутых программистов! Интересные обсуждения на актуальные темы и огромная аудитория, которая может быть интересна широкому кругу рекламодателей. У нас вы узнаете всё о компьютерах, базах данных, операционных системах, сетях, инфраструктурах, связях и программированию на популярных языках!
     Copyright © 2001-2024
    Реклама на сайте