HTA

Материал из Eludia.

Перейти к: навигация, поиск
Может, все уладится... Может быть, пламя погаснет... А лёд растает... пропасти зарастут... быть может... сады... сады...

Э. Ионеско, «Воздушный пешеход».

HTML Applications (HTA) — это технология, обладающая редкими и совершенно несовместимыми свойствами:

  • это невероятно просто для программиста и не требует ничего, кроме текстового редактора;
  • это придумано очень по делу и не тянет за собой ничего лишнего;
  • это реализовано только в MS и, похоже, последовательно отвергается конкурентами;
  • это практически не используется в информационных системах.

Более подробно (если вы об этом ещё не слышали): HTML Applications — это способ запуска графического ядра MSIE в виде специфического, облегчённого приложения (HTML Application host), что позволяет:

  • разом снять все вопросы, связанные с безопасностью;
  • избавиться от браузерного меню, справки, навигационных кнопок и горячих клавиш (всего, что так мешает в интерфейсах редактирования БД);
  • выделить WEB-приложению отдельное окно со своим заголовком и иконкой, видимое в списке задач, на нижней панели и т. д.;
  • создать в меню "Программы" (или "Автозапуск"), а также на рабочем столе ярлыки (shortcuts) с вашими фирменными иконками и горячими клавишами;
  • установить режим "одного окна" (single_instance), который в комбинации с горячим ключом делает окно приложения доступным за 1 клик вслепую, как бы ни был завален рабочий стол;
  • заблокировать выделение объектов на странице: при этом кнопки, свёрстанные в виде таблиц, кажутся монолитно отрисованными.

Содержание

Пример HTA-файла

Пишем для нашего приложения HTA (это стандартный HTML + один дополнительный тег)-файл следующего содержания:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<TITLE>Портал</TITLE>
<hta:application
	id="portal"
	applicationname="portal"
	border="thick"
	caption="yes"
	icon="http://portal/i/favicon.ico"
	navigable="no"
	scroll="no"
	selection="yes"
	showintaskbar="yes"
	singleinstance="yes"
	_windowState="maximize"
>
</HEAD>

<BODY
	leftMargin=0
	topMargin=0
	rightMargin=0
	bottomMargin=0
	scroll="no"
	onBeforeUnload="
		var src = document.frames[0].location.href + ;
		var m = src.match(/sid=(d+)/);
		if (m && m [1]) {
			window.open ('http://portal/?type=_logout&sid=' + m [1], 'invisible');
		}
	"
>

  <iframe
  	src="http://portal/"
  	application="no"
  	height=100%
  	width=100%
  	name="application_frame"
  	frameborder=0
  >

</BODY>
</HTML>

Здесь предполагается, что приложение доступно по адресу http://portal/. В вашем случае наверняка придётся заменить все строки, выделенные жирным.

Стоит обратить внимание на атрибут application="no". Если здесь указать 'yes', то приложение будет считать само HTA-окно за window.top. Однако содержимое этого окна не может перезагружаться по http-ссылке и туда не подключаются js-библиотеки Вашегол приложения. В результате ссылки с target="_top" будут открываться в новом окне браузера, а использование переменной window.top (в предположении, что туда подгружен navigation.js) будет порождать js-ошибки.

Скрипт на onBeforeUnload явно завершает сессию при закрытии окна. Разумеется, это срабатывает при доступности сервера в соответствующий момент. Впрочем, в случае некорректного выхода большой беды не случается, сессия удаляется по истечении установленного срока.

Фреймы: свои и чужие

Имя фрейма application_frame является зарезервированным и используется в Eludia, его переопределять не следует. У всех фреймов, вложенных в него, для вышеупомянутой опции application, как правило, следует проставлять значение "yes".

Однако в исключительных случаях, напротив, требуется изолировать фрейм и создать ему иллюзию главного окна. Такое случается при интеграции продвинутых инородных WEB-интерфейсов (например, почтовых).

Стандартные фреймы, такие, как invisible, всегда имеют опцию application="yes", но здесь возникает один важный момент: действия, связанные с генерацией ответов-файлов (например, выгрузка хранимых файлов или печать офисных документов) всегда должны производиться в целевой фрейм invisible. Если это не соблюдается, то возникает ошибка javaScript.

...
{
 href => "?type=prestation_type_files&id=$i->{id}&action=download",
 target => 'invisible',
},
...

Страница-заставка

Если есть риск, что WEB-приложение откликается с заметной глазу задержкой (а это, как правило, именно так), стоит задуматься о том, чем заменить настораживающий белый экран. Хороший вариант — страница-заставка с муляжом прогресс-индикатора. Для пущей красоты можно устроить переход на login-форму гладко, через page transition. Примерный HTML-код такой страницы (назовём её portal.html и расположим рядом с HTA-файлом):

<HTML>
<HEAD>
 <meta http-equiv="Page-Exit" content="progid:DXImageTransform.Microsoft.Fade(Duration=1)">
</HEAD>
<BODY BGCOLOR="#D6D3CE" onLoad="window.open('http://portal/?type=logon', '_self')">
 < table width=100% height=100% cellspacing=0 cellpadding=0 border=0>
  < tr>
   < td valign=bottom align=center style="font-family:Arial">
    Eludia is starting down...
   < /td>
  < /tr>
  < tr height=10>< td height=10> </ td></ tr>
  < tr>
   < td valign=top align=center>
    <img src="activity.gif">
   < /td>
  < /tr>
 < /table>
 </BODY>
</HTML>

Бесконечный градусник можно позаимствовать вот отсюда: [1].

Легко видеть, что URL приложения записан в onLoad страницы-заставки. Соответственно, в HTA-файле должна быть указана она сама.

 <iframe 
 	src="portal.html" 
 	application="yes" 
 	height=100% 
 	width=100% 
 	name="application_frame" 
 	frameborder=0
 >

Инсталляция

HTA-файл мыслится как полноправная Windows-программа, так что должен иметь соответствующего вида инсталлятор. При помощи Inno Setup это очень просто. Достаточно переписать ваш файл в чистую директорию, положить рядом favicon.ico и добавить к ним .iss-файл следующего содержания:

[Setup]
AppName=Portal
AppVerName=Portal 0.01
AppPublisher=Eludia
AppPublisherURL=http://www.eludia.ru
AppSupportURL=http://www.eludia.ru
AppUpdatesURL=http://www.eludia.ru
DefaultDirName={pf}\Portal
DefaultGroupName=Portal
OutputDir=.\__releases
OutputBaseFilename=setup
SetupIconFile=favicon.ico
Compression=lzma
SolidCompression=yes

[Languages]
Name: "eng"; MessagesFile: "compiler:Default.isl"
Name: "rus"; MessagesFile: "compiler:Languages\Russian.isl"

[Files]
Source: ".\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

[Icons]
Name: "{group}\Portal workflow"; Filename: "{app}\portal.hta"; IconFilename: "{app}\favicon.ico";
Name: "{group}\{cm:UninstallProgram,Portal}"; Filename: "{uninstallexe}"
Name: "{userdesktop}\Portal workflow"; Filename: "{app}\portal.hta"; IconFilename: "{app}\favicon.ico"; HotKey: "ctrl+alt+z"

[UninstallDelete]
Type: files; Name: "{app}\Internet shortcut.url"

[Run]
Filename: "{app}\portal.hta"; Flags: shellexec;

[UninstallRun]
Filename: "{app}\_scripts\uninstall.cmd"; Flags: runhidden

После чего открыть его Inno Setup Compiler'ом, отредактировать URL и заголовки — и нажать кнопку comiple. Мгновение — и инсталляционный комплект готов.

Публикация инсталлятора

Поскольку WEB-приложение — это своего рода сайт, логично сделать бинарный инсталлятор доступным как "файл для загрузки". Разместить его стоит туда же, куда все статические файлы приложения: в директорию /i.

Теперь — ссылка. Как правило, лучшее место для ссылки на него — форма авторизации. Правда, при использовании прозрачной авторизации (например, NTLM) эта страница может никогда не показываться, так что жёстких правил тут нет.

Во всяком случае, если вы размещаете ссылку не как основное содержимое страницы, а как дополнительную опцию, стоит позаботиться о том, чтобы она не была видна из-под самого HTA-файла. Для этого её видимость надо поставить в зависимость от имени текущего окна:

 <a href="/i/setup.exe">Установить...</a>

Нерешённые проблемы

Как бы ни было приятно использовать HTA, есть минимум 2 вопроса, которые заметно осложняют нам жизнь.

Внешние ссылки (почта)

Извещения по e-mail — стандартная функциональность WEB-приложений, востребованная многими заказчиками. Как правило, при этом требуется сопровождать письма ссылками на внутренние страницы системы. Например, ставить в извещении о подтверждении платежа ссылку на карточку этого платежа. Вполне логично.

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

  • сервер при отправке почты не имеет представления о том, в какую директорию установлен HTA-файл;
  • в режиме singleinstance происходит не открытие окна, а переключение на него, параметры при этом не могут быть переданы.

Можно было бы генерировать HTA-файлы на каждую карточку и слать их в качестве вложений в письма, однако даже если бы мы отказались от singleinstance (которы в данном случае порождает аналогичный логический конфликт), пришлось бы преодолевать защиту от HTA, которая встроена практически во все почтовые клиенты с тех пор как HTA широчайшим образом использовались какими-то хулиганами как платформа разработки вирусов.

Инсталляция вживую

Как бы ни был хорош Inno Setup, было бы ещё приятнее иметь возможность устанавливать HTA без предварительной компиляции инсталлятора. В частности, это позволило бы динамически записывать в HTA адрес, по которому обратился пользователь: ведь он может быть неизвестен на этапе разработки приложения, меняться при перенастройке сервера и т. д.

Можно перегенерировать setup.exe по запросу, однако Inno Setup доступен только для Windows, а большинство рабочих серверов приложения используют UNIX/Linux.

Другой вариант: генерировать на сервере VB-скрипт, который производит на клиенте все необходимые операции при помощи стандартных ActiveX-компонент. Процедура такой установки разработана, однако, к сожалению, использовать её практически невозможно, поскольку для неё требуется длительная работа по отключению нескольких каскадов безопасности на каждом рабочем месте.

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

Личные инструменты
Консультации
Разработчику
Администратору