ТаблицейБлоками.Приложение Д: объекты JavaScript innerText innerHTML window |
Последняя модификация: 10.08.2014 г
Страница загружена с адреса: http://webdesign.site3k.ru/conjuncture/append/d/price.html
Микрософт придумала очень эффективный способ обработки данных внутри эксплорера. Суть заключается в том, что база полностью загружается на компьютер, а потом обрабатывается без единого обращения в Интернет. Представьте себе, что вы хотите купить себе, к примеру, машину в каком-то большом салоне, и намерены ознакомиться с ассортиментом через Интернет, чтобы не шляться по салону целый день, и вернуться уставшим, но так и не сделавшим выбор. Вы входите на сайт выбранного салона и переходите к странице выбора модели
Дальше могут быть два варианта, в зависимости от того, будет ли обрабатываться база данных на сервере или нет:
Вот тут-то и оказывается весьма кстати новое изобретение Микрософта: браузер закачивает всю базу на компьютер, а потом обрабатывает, хоть в Off-Line. Конечно, глупо качать всю базу, если она занимает сто мегабайт, но если это обычный прайс, обычной фирмы сто, или даже тысяча наименований максимум сто килобайт веса. Ее качать-то всего 50 секунд, а постоянные запросы к SQL-серверу могли бы обернуться и пятидесятью минутами.
Так чем же отличается новая обработка от Микрософта от обычной выдачи всей базы данных?
Во-первых, форматом Микрософт придумал обрабатывать документы Excel и КомаДелиметеры (не знаю, как иначе назвать файлы формата .csv)!
В первом случае, вы создали документ Excel, кинули на сайт, а посетитель просматривает их прямо на Web-странице и, если предусмотрено, вносит изменения. Здорово? Да, только работает не на всех машинах, так как требует, чтобы был прописан определенный CLASSID. Прописан он у посетителя или нет, заранее не угадаешь, а уговаривать его, внести изменение в системный реестр дело рискованное: в ответ могут матюгами обложить.
Второй случай полегче. Редактировать серверную базу посетителю не позволяет (а обычно этого и не надо), зато использует широко распространенный CLASSID.
Файл csv тоже сделать не трудно, можно сделать лист Excel и сохранить его как csv, а можно написать и в блокноте.
Попробуйте создать в Excel табличку, представленную на рисунке
А затем сохраните ее как CSV (разделители запятые). Затем откройте полученный файл в блокноте и посмотрите на содержимое:
Модель;Холод;Тепло;Мощность;Площадь;Цена
Akai 07;2;2,1;700;18;370
Akai 09;2,1;2,3;900;25;390
Akai 12;3,2;4,1;1200;35;430
Akai 18;4,6;5,1;1800;60;680
То, что вы увидели, является истинным содержимым CSV-файла. Первая строка в нем определяет имена полей. Остальные строки являются записями данных. Каждое поле в записи, как и имена полей, отделены друг от друга точкой с запятой (в вашем случае может быть другой разделитель зависит от настроек системы). После последнего поля разделитель не допускается! Каждая запись отделена началом новой строки.
Такой файл действительно легко создавать в блокноте, особенно, если выровнять столбцы табуляторами и выбрать моноширинный шрифт (например, Courier New):
Модель; Холод; Тепло; Мощность; Площадь; Цена
Akai 07; 2; 2,1; 700; 18; 370
Akai 09; 2,1; 2,3; 900; 25; 390
Akai 12; 3,2; 4,1; 1200; 35; 430
Akai 18; 4,6; 5,1; 1800; 60; 680
Легко сделать и конвертацию данных, прямо из складской программы. CSV формат поддерживает не только обычный текст, но и другие типы данных. В таблице представлен полный перечень.
Тип данных | Значение |
---|---|
text | Текст, являющийся значением по умолчанию. Если тип поля не определен явно, считается что, он содержит обычный текст. |
date | Дата |
boolean | Логический (1 или 0) |
int | Целое число, без дробей |
float | Дробное число с плавающей точкой |
Таким образом, CSV-файл поддерживает почти все необходимые базе данных форматы, а те, что не поддерживаются, можно сохранять как обычный текст. Используя поддерживаемые форматы данных, можно уточнить, какие данные хранятся в том или ином столбце, указав, через двоеточие, после названия полей их тип:
Модель:text; Холод:float; Тепло:float; Мощность:int; Площадь:int; Цена:int
Akai 07; 2; 2,1; 700; 18; 370
Akai 09; 2,1; 2,3; 900; 25; 390
Akai 12; 3,2; 4,1; 1200; 35; 430
Akai 18; 4,6; 5,1; 1800; 60; 680
Это может оказаться важным, так как, при сравнении, например текстовых полей, со значением «04» и «4», получается неравенство, а при сравнении числовых полей с тем же значением равенство, так как 4 и 04 это одно и то же количество.
Несмотря на то, что CSV-файл позволяет сохранять заголовки на русском языке и с пробелами, во избежание неожиданностей, лучше сохранять их на английском и не включать пробелы. Например:
model:text; cool:float; hot:float; power:int; place:int; price:int
Akai 07; 2; 2,1; 700; 18; 370
Akai 09; 2,1; 2,3; 900; 25; 390
Akai 12; 3,2; 4,1; 1200; 35; 430
Akai 18; 4,6; 5,1; 1800; 60; 680
Включение CSV-файла в web-страницу обеспечивается элементом <OBJECT>
</OBJECT>. Полное его описание представлено в документации по HTML. В нашем случае, полезны только часть его свойств:
<object CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83" id="datProduct" width="0" height="0">
<param name="DataURL" value="price.csv">
<param name="UseHeader" value="true">
<param name="CaseSensitive" value="false">
<param name="CharSet" value="windows-1251">
<param name="EscapeChar" value="\">
<param name="FieldDelim" value=";">
<param name="dataformatas" value="text">
</object>
CLASSID это определение, какого типа объект требуется включить в страницу. Для CSV-файла это clsid:333C7BC4-460F-11D0-BC04-0080C7055A83 (Да, не выговоришь, на трезвую).
id идентификатор назначаемый объекту обязателен, так как будет использоваться в дальнейшем.
Атрибуты величины заданы, чтобы браузер не пытался что-либо отразить на месте включения объекта, так как фактическое его отображение должно происходить в другом месте.
Главные определения перечислены в тегах PARAM NAME, внутри <OBJECT> </OBJECT>.
DataURL определяет файл с базой данных.
UseHeader Если TRUE, первая строка считается заголовком и служит для облегчения обращения к данным, если FAALSE, первая строка считается данными, типы полей текстовые и обращение к ним возможно только как Column1, Column2 и т. д.
CaseSensitiv Если TRUE, маленькие буквы и большие буквы считаются различными буквами, ИВАНОВ и Иванов два разных человека.
CharSet Используемый набор символов, должен соответствовать использованному в базе (если пишется из русской Windows, это windows-1251).
EscapeChar Символ, подавляющий стандартное значение идущего за ним символа. Например, если поля разделены точкой с запятой, то для включения точки с запятой в текст, перед ней нужно поместить такой символ.
FieldDelim Символ, разделитель полей. Обычно либо точка с запятой, либо табуляция, либо запятая.
TextQualifier Определяет символы, в которые могут заключаться значения текстовых полей, если те содержат недопустимые символы.
dataformatas Определяет, отображать содержимое ячеек как текст (text) ил учитывать HTML-форматирование (HTML). Может иметь неопределенное значение (localized-text).
Определив параметры используемого объекта, можно включить его в таблицу:
<table dataSrc="#datProduct">
<thead>
<tR>
<tH>Модель
<tH>Холод (кВт.)
<tH>Тепло (кВт.)
<tH>Мощность (Ват)
<tH>Площадь (М<sup>2</sup>)
<tH>Цена ($)
</tr>
</thead>
<tbody>
<tr>
<td><div datafld="model"></div>
<td><div datafld="cool"></div>
<td><div datafld="hot"></div>
<td><div datafld="power"></div>
<td><div datafld="place"></div>
<td><div datafld="price"></div>
</tr>
</tbody>
</table>
dataSrc в этой таблице, должен указывать на идентификатор ранее объявленного объекта. Перед идентификатором должен стоять знак решетки (#datProduct).
datafld в ячейке, должен указывать на поле, которое следует в нее выводить.
Теперь сохраняем страничку, сохраняем CSV-файл и смотрим на результат. Данные кома-делимитера должны были оказаться внутри веб-страницы.
Ну и что? Скажете вы, можно было просто написать таблицу и вставить во внутрь страницы, или, если требуется обновлять ее отдельно, включить ее SSI-инструкцией!
Да, все верно, но вы когда-нибудь видели нормальные программы для работы с базами данных? Скорей всего «Нет». Я уверен в этом, потому что сам, профессионально работаю с базами данных, а нормальных программ практически не встречал. Между тем, новая выдумка Микрософта позволяет их делать. Достаточно немного усложнить таблицу:
<table dataSrc="#datProduct" id="TabProduct" border=1 style="border-collapse:collapse; background:#FFFFF0">
<CAPTION><span id="coment"><EM>Продажа кондиционеров и сплит-систем с доставкой и установкой</EM></span></CAPTION>
<COL style='white-space:nowrap'><COL align=center><COL align=center><COL align=center><COL align=center><COL align=right>
<thead>
<tR style="cursor:hand; background:#ccffcc">
<tH title="Сортировать по модели" onclick="VarWindow.setSort(1);"><span id=head1 style='font-family:Symbol;color:green'></span>Модель
<tH title="Сортировать по холоду" onclick="VarWindow.setSort(2);"><span id=head2 style='font-family:Symbol;color:green'></span>Холод (кВт.)
<tH title="Сортировать по теплу" onclick="VarWindow.setSort(3);"><span id=head3 style='font-family:Symbol;color:green'></span>Тепло (кВт.)
<tH title="Сортировать по мощности" onclick="VarWindow.setSort(4);"><span id=head4 style='font-family:Symbol;color:green'></span>Мощность (Ват)
<tH title="Сортировать по площади" onclick="VarWindow.setSort(5);"><span id=head5 style='font-family:Symbol;color:green'></span>Площадь (М<sup>2</sup>)
<tH title="Сортировать по цене" onclick="VarWindow.setSort(6);" align=center><span id=head6 style='font-family:Symbol;color:green'></span>Цена ($)
</tr>
</thead>
<tbody>
<tr>
<td><div datafld="model"></div>
<td><div datafld="cool"></div>
<td><div datafld="hot"></div>
<td><div datafld="power"></div>
<td><div datafld="place"></div>
<td><div datafld="price"></div>
</tr>
</tbody>
</table>
А в определение объекта добавить реакцию на событие:
ondatasetcomplete="numberRow();"
Затем, после таблицы вписать вызов функции:
<SCRIPT LANGUAGE="JavaScript"><!--
setSort(1);
//--></SCRIPT>
И создать элемент управления:
<table style="border-collapse:collapse;border-right:outset 2px;border-left:outset 2px">
<tr>
<td style="font-size:80%;background-color:navy;color:white;Padding-left:5pt ;border-top:outset 2px">Выберите себе кондиционер по :</b>
</tr>
<tr>
<td style="background-color:#66ccff;Padding:5pt;border-bottom:outset 2px">
<form name="form1" method="GET" action="">
<P><input style="float:right;margin:1px" type="TEXT" size="5" name="edit1" value="">Цене до...($)
<p><input style="float:right;margin:1px" type="TEXT" size="5" name="edit2" value="">Площади от... (м<sup>2</sup>)
<p>Фирме-производителю
<select name="menu">
<option selected>Все
<option>Akai
<option>Akira
<option>Fujitsu
<option>Hitachi
<option">Midea
<option>Mitsubishi
<option>Samsung
<option>Sharp
<option>Toshiba
<option>Yoko
</select>
</p>
<p><INPUT TYPE='button' VALUE='Показать' onClick="setFilter();">
<input type='button' value='Снять фильтр' onClick="RESETFilter();">
</form>
</TR>
</table>
Обратите внимание: В элементе управоения появилась не используемая ранее «Фирма-производитель». Это поле необходимо добавить к таблице, чтобы можно было выбирать не только по конкретным моделям, но и по производителю.
Фактически, база приобретает такой внешний вид:
mark:text; model:text; cool:float; hot:float; power:int; place:int; price:int
Akira; Akira 07; 2; 2,2; 700; 18; 320
Akira; Akira 10; 2,3; 2,5; 1000; 25; 335
Akira; Akira 13; 3,6; 4,2; 1300; 35; 350
Akira; Akira 19; 4,8; 5,1; 1900; 60; 550
Akira; Akira 24; 6,6; 7,2; 2400; 90; 740
Теперь осталось только внести немного скриптов в заголовочную часть страницы:
Во-первых, в скриптах, меняющих сортировку, фильтры и заголовки используются свойства innerText и innerHTML. Первое из них определяет текст, содержащийся в элементе, второе, его HTML-код (вместе с текстом). Благодаря ним, меняется содержимое некоторых элементов. Например, чтобы в заголовке таблицы отобразить жирную красную надпись «Кондиционеров с указанными параметрами не найдено», следует задать ему innerHTML=<B><font color=red>Кондиционеров с указанными параметрами не найдено</font></b>.
Во-вторых, в скриптах используется метод dataSrc для таблицы, определяющий источник данных.
В-третьих, используются такие методы объекта как Filter, Sort и Reset(), определяющие критерии отбора данных и порядок сортировки и, вынуждающие объект инициализироваться заново.
В-четвертых, используются свойства внутреннего объекта recordset, вложенного в используемый объект. Объект recordset является частью всего объекта базы данных и указывает на отдельную ее запись. В данных скриптах используются следующие его методы: AbsolutePosition и MoveNext(). Первый из них определяет позицию записи в заданной выборке, а второй инициализирует переход к следующей записи по этой же выборке.
В-пятых, используется событие ondatasetcomplete, происходящее в объекте при окончании загрузки данных.
В-шестых, используется событие onClick на заголовках таблицы для смены порядка сортировки при щелчке по заголовку и событие onClick на кнопках, для смены фильтров при щелчке по кнопке.
Теперь, немного разобравшись в используемых свойствах, методах и событиях, можно проанализировать весть код.
Основным элементом управления для просмотра базы данных является табличка с кнопками, выпадающим списком и двумя полями ввода:
Эта табличка определяет фильтры для выборки данных. Наиболее приметным ее элементов является выпадающий список, основная особенность которого состоит в том, что на него не назначено никаких событий и все определение ограничивается строкой <select name="menu">. Так как создание фильтра не ограничивается одним лишь выбором торговой марки из списка, изменения в списке не должны вызывать никакой реакции. Применение фильтра, чтобы не загружать процессор лишней суетой, должно происходить только по окончании его настройки, подтверждаемой нажатием кнопки «Показать». Именно после нажатия этой кнопки запускаются механизмы фильтрации.
Другой особенностью списка является отсутствие у его элементов option каких-либо значений. Значения не нужны этим элементам, так как для определения требуемого фильтра используется innerText выбранной строки из массива меню (команда menu[menu.selectedIndex].innerText). Такой метод позволяет избежать ошибки, которая могла бы возникнуть по мере эксплуатации и периодического изменения значений, когда, в результате невнимательности, значение могло бы не соответствовать отображаемому тексту.
При нажатии на кнопку «Применить», запускается процедура setFilter(), являющаяся основой всех остальных издевательств над базой данных. Рассмотрим ее подробней:
В начале процедуры сохраняется значение прежнего фильтра (если таковой был), в переменной OldFilter. Это необходимо для сравнения нового фильтра, после его установки, со старым. Если сравнение даст равенство (значение фильтра не изменилось), никаких действий выполняться не будет, чтобы не отнимать процессорное время. Смена фильтра произойдет, только если изменилось его значение.
Затем текущее значение фильтра MyFilter обнуляется и определяется заново в соответствии с условиями.
В конце процедуры проверяется, изменился ли фильтр, в сравнении с предыдущим и, если значения не равны, у таблицы отнимается источник данных (TabProduct.dataSrc=""), к объекту применяется новый фильтр (datProduct.object.Filter = MyFilter) и производится его новая инициализация (datProduct.object.Reset()), после чего таблице заново указывается источник данных (TabProduct.dataSrc="#datProduct") и она перечитывает переинициализированный объект.
Функция RESETFilter(), вызываемая по нажатию другой кнопки в табличке, сбрасывает значение полей и выпадающего списка в исходное состояние, а затем вызывает функцию setFilter(). При пустых полях фильтрации, функция setFilter() устанавливает для объекта пустое значение фильтрации и, если раньше оно было другим переинициализирует объект и таблицу отображения данных:
Как только, при загрузке страницы или после изменения фильтра, в объекте загружаются данные, по событию ondatasetcomplete вызывается функция numberRow().
Эта функция инициализирует переменную «i» и заранее назначает в элемент с идентификатором «coment» innerHTML со значением «<B><font color=red>Кондиционеров с указанными параметрами не найдено</font></b>» (кричащая красная надпись о слишком суровом условии подбора). Дальше начинается цикл по всем записям отфильтрованной базы. Переход к следующей записи происходит с помощью функции MoveNext, перед выполнением которой текущая позиция в базе данных сохраняется в переменной «i». Как только программа перечитает все записи соответствующие условиям фильтра и выйдет за их придел, показатель позиции (datProduct.recordset.AbsolutePosition) приобретет отрицательное значение что, с одной стороны, приведет к назначению элементу «coment» нового текста, состоящего из значения переменной comentText (назначаемого в процедуре setSort), количества насчитанных в соответствии с фильтром строк и значения, возвращаемого функцией SetString, вызванной с параметром «i», а с другой, к прекращению цикла, так как «i» становится больше datProduct.recordset.AbsolutePosition. В результате, в верхней части таблицы указывается либо надпись о слишком строгом фильтре, либо точное количество записей, соответствующих условию.
Фукция setSort, определяет не только переменную comentText, участвующую в формировании надписи, но и порядок сортировки. Со страницы она вызывается щелчком по заголовкам столбцов таблицы, с параметром, определяющим номер столбца (номер сортировки).
Функция имеет более длинный код, чем предыдущие:
Однако его величина не означает сложности, потому что вся суть кода сводится к тому что:
Другая функция SetString используется для определения правильного склонения:
Первая строка функции (NumString="?" + NumString;) превращает переданный ей параметр в строку. Применяемый в ней способ не совсем правильный. Но дальше удобно оперировать со строкой. Так как, когда мы обращаемся к элементам строки по индексу, мы должны указывать индекс на единицу меньший, чем номер элемента (первый элемент имеет нулевой индекс). А в этом случае, нулевой индекс уже забит не имеющим для нас значение символом и, мы обращаемся к первому значимому элементу, как к элементу под первым, а не нулевым номером. В данной функции это вообще не имеет значение, так как элементы будут браться только с конца, но обычно я делаю именно так, и применил этот метод по привычке, а теперь не исправляю, чтобы показать, что можно и так.
Дальше идет анализ последних символов строки. Функция substr выделяет часть строки, начиная с символа, номер которого задается длинной строки (NumString.length), минус некоторое количество символов. Длина выделенной части строки всего один символ. Его достаточно для правильного определения склонения. Важно лишь знать, в какой ситуации брать последний символ, а в какой предпоследний и не допустить продолжения работы алгоритма, если предпоследний символ единица.
В данную функцию можно не вникать. Она вполне универсальна и может быть скопирована в любой другой код без изменений. Максимум, что может потребоваться, так это замена слова «модель», на что-то другое, например, рубль, доллар, килограмм, штука, бутылка и т. д.
Осталось только пояснить положение некоторых переменных и вызовов.
comentText инициализируется в начале скрипта до объявления функций, так как используется в нескольких функциях и, значение, определенное ей в одной функции, затем используется в другой.
ascent1 ascent6 инициализируются вне использующей их функции, чтобы хранить значения между вызовами функции.
MyFilter, как и предыдущие, инициализируются вне использующей ее функции, чтобы хранить значение между вызовами функции.
numberRow() вызывается по событию ondatasetcomplete объекта, чтобы пересчитать количество строк именно после того как данные будут получены, а не во время получения или до. Фактически, если фильтр не изменился, ее можно не вызывать. Но при первой загрузке данных, она должна быть вызвана, чтобы показать общее количество записей. Объявление функции должно находиться перед вызовом, поэтому на странице сначала помещен скрипт, а затем объект.
setSort(1) устанавливает начальный порядок сортировки по возрастанию модели. Функция использует идентификаторы таблицы, так что, ее вызов должен происходить после их определения (после таблицы) и желательно до полной загрузки страницы (до события OnLoad документа), чтобы как можно быстрее задать правильную сортировку. Ее можно задать в самом определении объекта, но тогда нужно сразу определить и соответствующий заголовок. Я поленился писать лишние буквы.
Вы, наверное, уже заметили, что предлагаемые здесь фокусы работают не во всех браузерах? Решение этой проблемы предложено на странице Обработка баз данных сервером. Но не спешите на нее переходить. Ведь предлагаемая мной обработка баз данных в эксплорере происходит так замечательно, что мне не хочется отказываться от этой идеи и, я предлагаю сделать ее еще эффектней.
Вам не показалось что, размещение таблички с элементами управления просмотром на той же странице, что и сама база, не самое изящное решение? Ведь ее можно вынести оттуда и поместить в отдельное окно. При чем, не просто там, какое-то окно, а window.showModelessDialog!
Модифицируем страницу, выкинув из нее все скрипты и поместив открытие окна window.showModelessDialog:
<SCRIPT LANGUAGE="JavaScript"><!--
a=screen.availWidth -250; // Определение размеров экрана для последующего задания позиции окна
b=screen.availHeight-155;
VarWindow=showModelessDialog('controls2.html',window,'status=no;scroll=no;resizable=no;dialogWidth:250px;dialogHeight:160px;dialogLeft:' + a +'px;dialogTop:' + b +'px;');
//--></SCRIPT>
Поскольку мною планируется открыть окно размером 250х160 пикселей внизу справа, первая строка скрипта вычисляет будущее горизонтальное положение его верхнего левого угла, вычитывая 250 пикселей из разрешения экрана (screen.availWidth), а вторая вертикальное. Последняя команда скрипта открывает файл с элементами управления в showModelessDialog, определив его параметры:
status=no; не отображать панель статуса.
scroll=no; не отображать панель скроллинга.
resizable=no; не позволять менять размер.
dialogWidth:250px; ширина 250 пикселей.
dialogHeight:160px; высота 160 пикселей.
dialogLeft:' + a +'px; отступ слева задан переменной a.
dialogTop:' + b +'px; отступ справа задан переменной b.
Описание метода window.showModelessDialog смотрите на странице Ссылки и окна. Внешний вид и внутреннее содержание..
Скрипты теперь будет находиться в window.showModelessDialog и их никто не сможет увидеть (это конечно не главное, но заставит понервничать конкурентов бессильных понять, как это все работает). Для обращения к ним, вместо setSort(1) и numberRow() придется использовать VarWindow.setSort(1) и VarWindow.numberRow() (раз мы назначили этому окну такой идентификатор). Но это нас не сильно затруднит. В самом showModelessDialog придется поработать больше.
Чтобы открытое нами второе окно получило доступ к данным первого, внутри второго окна, первому окну требуется назначить идентификатор:
vVariables = window.dialogArguments;
Теперь можно проверить, правильно ли открыто диалоговое окно:
if (vVariables) // если окно открывается как немодальное (как задумано), переменная определена.
{
OpenerLocation=vVariables.location;
} else { // Если нет - страницу пытаются открыть, минуя прайс (почитали исходный текст прайса).
document.location.replace('price2.html'); // не тут-то было. Перебросим на прайс, даже не оставив
} // запись о странице управления в истории посещений
// управляющие скрипты посмотреть не удастся (если не найти их в кеше)
Теперь мы уверены, что окно управления открыто, как положено. А нам нужна эта уверенность: если будет открыто только управляющее окно, попытка изменения фильтров приведет к сообщениям об ошибках, а мы не собираемся портить себе репутацию только из-за того, что посетитель не с того конца начал.
Перебрасываем на страницу управления скрипты, не забыв перед обращением к свойствам открывшего окна добавить vVariables:
Создаем табличку с элементами управления (хотя здесь это не обязательно должна быть таблица, важло лишь точно задать размеры и положение элементов, так как планируется запрет на изменение размеров окошка):
Для пущего эффекта, можно добавить реакцию на событие onhelp, происходящее при щелчке мыши после нажатия на значок помощи «?» или нажатии клавиши F1, и всплывающую подсказку (title).
Все. Сохраняем и получаем удовольствие.
Полученный элемент управления можно перетаскивать куда угодно, чтобы он не заслонял основное окно. При необходимости, его можно закрыть, и тогда, для его открытия, нужно лишь нажать на кнопку «Обновить» на странице прайса.
Одна только проблема мешает получить чувство полного удовлетворения: showModelessDialog работает в IE только начиная с версии 5.0. Возможно вскоре, с базами данных и showModelessDialog будут работать все браузеры, потому что, это действительно здорово, но пока требуется создавать универсальные страницы.
Предложенный метод создания прайсов, а может и не только их, настолько интересен своими скоростями, а плавающее окно настолько удобно, что их применение может иметь смысл даже, несмотря на то, что другие браузеры их не поймут. Просто нужно сделать так, чтобы использовался то метод, предложенный здесь, то метод, предложенный на Обработка баз данных сервером, в зависимости от того, поддерживается первый или нет. Причем, не следует заранее пытаться определить, будет ли поддерживаться метод или нет, так как, можно предполагать что, метод не поддерживается в браузере Опера, а новая версия Оперы может его поддерживать. Или можно предполагать что, метод поддерживается шестым IE, а у посетителя может оказаться заблокировано динамическое содержание страницы. Поэтому, наиболее надежным является определение возможности или невозможности метода, используя сам метод.
Например, для определения, открывается ли showModelessDialog, перед его выполнением можно инициализировать некую переменную, установив ее значение в ложное, а после выполнения, переустановить ее значение в истину. Поскольку выполнение скрипта обрывается, как только встречается нераспознанная инструкция, переменная не установится в истину если showModelessDialog не распознан:
<SCRIPT LANGUAGE="JavaScript"><!--
VarWindow='';
NoError='FALSE';
a=screen.availWidth -250;
b=screen.availHeight-160;
VarWindow=showModelessDialog('controls2.html',window,'status=no;scroll=no;resizable=no;dialogWidth:250px;dialogHeight:160px;dialogLeft:' + a +'px;dialogTop:' + b +'px;');
NoError='TRUE';
//--></SCRIPT>
Можно и не задавать отдельной переменной, а использовать ту, что используется для запуска окна showModelessDialog, но в отдельном скрипте (так как после неудачной инструкции, выполнение текущего скрипта прекращается):
<SCRIPT LANGUAGE="JavaScript"><!--
VarWindow='';
a=screen.availWidth -250;
b=screen.availHeight-160;
VarWindow=showModelessDialog('controls2.html',window,'status=no;scroll=no;resizable=no;dialogWidth:250px;dialogHeight:160px;dialogLeft:' + a +'px;dialogTop:' + b +'px;');
//--></SCRIPT>
<script LANGUAGE="JavaScript"><!--
if (VarWindow)
{
// VarWindow удалось открыть
}else{
// VarWindow не удалось открыть
}
//--></script>
Определить, загружаются ли данные в объект, еще проще: достаточно во внутрь объекта поместить что-то, должное запускаться при сбое объекта. Тогда, если объект поддерживается, оно не будет выполняться, а если не поддерживается, будет выполнено:
<object CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83" id="datProduct" width="0" height="0" ondatasetcomplete="VarWindow.numberRow();">
<param name="DataURL" value="price.csv">
<param name="UseHeader" value="true">
<param name="CaseSensitive" value="false">
<param name="CharSet" value="windows-1251">
<param name="EscapeChar" value="\">
<param name="FieldDelim" value=";">
<param name="dataformatas" value="text">
<font color=red><P>Объект не поддерживается вашим браузером! Если вы хотите увидеть данные, откройте, пожалуйста это окно в Internet Explorer не ниже 5.0.</P></font>
</object>
В результате, можно получить такой вариант (точное решение зависит от личных предпочтений): Смотреть.