Web-интерфейс для FoxPro-программы | |
---|---|
maple4 Автор Сообщений: 210 Откуда: Москва Дата регистрации: 26.10.2007 |
Генератор Интерфейса 1.0.0
Прямая ссылка на архив (450 кб, исходники + 7za.exe): www.maple4.ru Для чего? Формирование HTML-Интерфейса для программы, написанной на FoxPro. Зачем? Без сложных ухищрений FoxPro создает только "стандартный" интерфейс, который в настоящий момент выглядит несколько аскетично. Программа может предоставить интерфейс "как-бы" в стиле web - без установки каких-либо дополнительных сервисов (например IIS или сервера Апач ). Что дает web-интерфейс? Естественно (ради этого все и задумывалось), гораздо большие возможности по графическому оформлению. Используя Javascript, можно добиться таких спецэффектов, что дух захватывает - плавающие разделы, напоминания, часы, календари и т.д. - все зависит от знания этого самого javascript. Простое размещение видео (+ роликов с youtube), флеш-анимации, файлов мультимедиа непосредственно на форме - еще один плюс web-интерфейса. Где еще можно применить данную разработку? Программа ИДЕАЛЬНО подходит для создания пошаговых игр (и все это - средствами FoxPro). Или, например, "электронных" книг с реакцией на действия пользователя (по сути - получается все та же пошаговая игра Помню время, когда компьютеров не было, были очень распространены книги с сюжетом, зависящим от случайности и личным предпочтением читателя. Это лирическое отступление , но вторым приложением в примере будет "Стань Стальной Крысой!" Г. Гаррисона. Как бы авторские права не нарушить...). Или, еще вариант, загрузчиков/инсталляторов с CD/DVD-ROM. И вот еще... Применяя javascript ВМЕСТЕ с FoxPro (при обработке может использоваться код FoxPro, а не только javascript - представьте, какие открываются горизонты), можно создавать код, срабатывающий по какому-либо событию (например, после нажатия кнопки или в момент времени) и не требующий переформирования всей страницы. Данная возможность "выросла" из примера на странице forum.foxclub.ru (Роме - спасибо). При том, что данная возможность - самая интересная, используется она до обидного меньше всего. Одна из причин - я не совсем разобрался с JavaScript. Подробнее - чуть ниже ("Альтернатива <action>"). Ну и отдельное спасибо piva - за "запрет" возможности перехода на предыдущую страницу по Backspace или Alt-X, причем БЕЗ применения JavaScript. Приложенный пример (проект 2x2) всего лишь демонстрирует возможности проекта, вот только выглядит не очень (нет оформления, файлов графики и т.д.). Причина банальна - не хватает времени. Даже не нарисовать, не хватает времени просто найти рисунки в Интернет-е ОЧЕНЬ нужны анимированные gif-картинки золотых, серебряных и медных монет с прозрачным слоем для использования в любом фоне. Заранее спасибо! "Защита" с логином/паролем не претендует на что-либо, кроме демонстрации. Согласен, в дальнейшем по тексту "многа букафф"... что делать. Во первых, хотелось сразу ответить на предполагаемые вопросы, а во вторых - по возможности дать некий пример использования. Символами --------------------------------------------- отмечены логические разделы, по первой строке которого можно понять, читать дальше или нет. Особенности программы - весь код в основном размещается в HTML-странице (т.е. в бланке). Но программный код, при необходимости (например, для исключения дублирования), можно вывести в отдельный prg-файл (будет находиться в рабочем каталоге/подкаталоге). Конечно же, самый "удобный" вариант - включить foxpro-код непосредственно в исполняемый exe-модуль, но предлагаю делать это в самых крайних случаях - для обеспечении безопасности или повышения скорости обработки. На разработку проекта повлияли некоторые знания в ASP.NET и PHP (будь оно все неладно...) --------------------------------------------- Создание интерфейса. Процесс создания разбивается на несколько шагов. I. Каркас. Необходимо создать набор html-страниц (далее -> gi-форм), оформленных в виде небольшого сайта: меню, кнопки, картинки, ссылки на ресуры в Интернет (например - на видео Ютуба) и т.д. Названия gi-форм ДОЛЖНЫ начинаться с m4gi_ (признак gi-формы, без этого gi-форма обрабатываться НЕ БУДЕТ), а в содержимом - должен быть код <!--m4gi (признак правильной gi-формы, начало комментария html, и одновременно - процедуры инициализации и настройки) ! II. Наполнение. 1. В теле каждой gi-формы нужно разместить код загрузки и обновления load (аналог FoxPro : Load ) и init ("аналог" Init или Refresh FoxPro). 2. Нужно создать ссылки (или изменить существующие) для запуска gi-форм с параметрами (аналог FoxPro - передача параметров в форму) - добавление реакции. Переданные параметры gi-форма будет обрабатывать в load перед формированием страницы и в init после формирования. 3. Нужно разместить в gi-формах специальные теги - управляемые элементы. Их назначение - в нужных местах gi-формы вставить текст: - значения полей, функций или переменных или код FoxPro, который сформирует нужный текст. --------------------------------------------- Настройки формы. ВАЖНО! Даже если в настройках ничего не будет размещаться - ОБЯЗАТЕЛЬНО добавьте в страницу хотя бы текст <!--m4giproperties --> Настройки задаются в секции <!--m4giproperties -->, пока в этой конструкции можно разместить только процедуру load Подпрограммы gi-формы: <load> Текст программы foxpro</load> ПодПрограмма инициализации gi-формы Срабатывает ПЕРЕД формированием страницы. Здесь размещается код, необходимый для генерации HTML-страницы - открытие таблиц, создание глобальных переменных. <init> Текст программы foxpro</init> ПодПрограмма обновления gi-формы Срабатывает ПОСЛЕ формирования страницы. В init можно разместить запуск таймеров и кода обновления HTML-элементов уже сформированной страницы. load и init срабатывают и при загрузке новой страницы, и при обновлении текущей. Просто одна - до формирования, а другая - после формирования. Пример размещения можно посмотреть в разделе "Пример типичной gi-формы". --------------------------------------------- 1. Каталог запуска программы - это каталог, где запускается exe-модуль. Обычно в этом каталоге размещаются общие таблицы/файлы для всех приложений или общие таблицы/файлы для всех пользователей, архивы, распаковываемые в дальнейшем в рабочий каталог. 2. Каталог интерфейса - место, где находятся html-формы и процедуры интерфейса. Каталог интерфейса может быть одновременно рабочим каталогом (что такое рабочий каталог - чуть ниже). 3. Рабочий каталог - это место, где будут формироваться готовые страницы. Зачем? Представьте, что Вы создаете интерфейс для программы, которая будет находиться на CD-ROM. Куда будут формироваться готовые страницы, если CD-ROM НЕ ПОЗВОЛЯЕТ записывать на него информацию (только считывание)? Рабочий каталог эту проблему снимает: Во время ПЕРВОГО запуска все файлы из каталога интерфейса переносятся в рабочий каталог, а уже в рабочем каталоге формируется то, что надо! В случае, если программа НЕ находится на CD/DVD-ROM (т.е. запускается прямо с жесткого диска) рабочим каталогом является каталог интерфейса. В этом случае НЕТ затрат времени на копирование и html-страницы формируются там же, где находятся gi-формы и процедуры интерфейса. --------------------------------------------- Объекты post и this_form В процедурах load и init (а так же во всех <fp></fp>-тегах) при обработке доступны специальные объекты post и this_form. 1. post Если gi-форме были переданы параметры - ВСЕ свойства этих параметров доступны через работу с этим объектом (нужно учитывать, что все параметры - текстового вида). 2. this_form с помощью этого объекта Вы можете напрямую обращаться к свойствам и методам foxpro-формы. *Например, можно задать заголовок окна: this_form.caption="Новый заголовок" *или изменить ширину и высоту окна: this_form.width=800 this_form.height=600 --------------------------------------------- Управляемые элементы вставляются специальными тегами - <fp></fp> Два способа вставки: 1. Внутри может размещаться функция, переменная или поле - ОБЯЗАТЕЛЬНО первым символом должне быть амперсанд - & Пример: Текущие дата/время: <fp>&datetime()</fp> 2. Внутри может размещаться код FoxPro. Если результат будет возвращен оператором Return - текстовое значение результата будет вставлено при формировании страницы. Пример: Текущие дата/время: <fp>local ii ii=datetime() return ii</fp> --------------------------------------------- Нужно "научить" формы реагировать на клики (по кнопкам, ссылкам, рисункам и т.д.). Реакция задается специальными тегами <action> </action>, внутри которых размещается код обработки: 1. внутри ссылки <a href="<action>ЗДЕСЬ"</action>></a> 2. внутри формы <form action="<action>ЗДЕСЬ"</action>></form> Есть еще один вариант с javascript - но об этом снова чуть ниже. Типичные примеры использования: Переход к странице, находящейся в рабочем каталоге <a href="<action>return '/m4gi_gl_form.html?session=_vbrtdgd&uroven=1'</action>">I уровень</a> или <a href="<action>&'/m4gi_gl_form.html?session=_vbrtdgd&uroven=1'</action>">I уровень</a> Переход к странице, которая находится в подкаталоге 2x2 рабочего каталога программы <a href="<action>return '/2x2/m4gi_2x2_form.html?session=_vbrtdgd&uroven=1'</action>">I уровень</a> или <a href="<action>&'/2x2/m4gi_2x2_form.html?session=_vbrtdgd&uroven=1'</action>">I уровень</a> Закрытие формы ссылкой <a href="<action>this_form.close</action>">Закрыть окно</a> Закрытие формы кнопкой <form name="main_form" id="main_form_id" method="post" action="<action>this_form.close</action>" onsubmit="return false;"> <input type="button" value="Закрыть" onclick="submit();"> Открытие gi-формы в новом окне: <a href="<action>m4gi_newform('\m4gi_magazin.html')</action>">К магазину!</a> Присвоение глобальным переменным значений <a href="<action> _m4gi_type_app='2x2' _m4gi_type_lg=1 </action>">Присвоить</a> Задание реакции в форме - с передачей процедуре (которая находится в корне рабочего каталога программы) текущих параметров <form name="main_form" id="main_form_id1" method="post" action="<action>return m4gi_exec('/prg_m4gi_avtoriz.prg',post,this_form)</action>" onsubmit="return false;"> Необходимо авторизоваться (что-бы понять, а кто, собственно, здесь).<br><br> <br>Введите имя: <input type="text" name="text_name" id="text_id1" value="" /> <br>Введите пароль: <input type="password" name="text_pwd" id="text_id2" value="" /> </form> <input type="button" value="Войти" onclick="document.forms['main_form'].submit();"> Задание реакции в форме - с передачей процедуре (которая находится в подкаталоге 2x2 рабочего каталога программы) текущих и дополнительных параметров <form name="main_form" id="main_form_id1" method="post" action="<action>return m4gi_exec('/2x2/prg_m4gi_2x2_prover.prg',post,this_form,1,2)</action>" onsubmit="return false;"> <INPUT TYPE="text" NAME="proiz" ID="text_proiz" VALUE="" /> <input type="button" value="Ответить" onclick="submit();"></form> Задание реакции в форме - с открытием другой gi-формы: <form name="test_form_name" id="test_form_id" method="post" action="<action>return '/2x2/m4gi_2x2_start.html'</action>" onsubmit="return false;"> <br><b>Name?</b> <br><input type="text" name="fio" id="text_id" value="" /><br/> <br><textarea name="textarea_notes" id="textarea_id" cols="20" rows="5" ></textarea><br/> </form> <br> <input type="button" value="Отправить" onclick="document.forms['test_form_name'].submit();"> Далее, при нажатии кнопки Отправить, данные со страницы (значение полей в fio и textarea_notes) будут переданы заданной в <form action... gi-форме. Обратите внимание, method="post" ! Далее, в gi-форме /2x2/m4gi_2x2_start.html будут доступны параметры post.fio и post.textarea_notes, которые можно будет использовать при формировании страницы. Внутри тегов <action></action> могут размещаться теги <fp></fp> для формирования нужного кода реакции. Например, открытие страницы в подкаталоге 2x2 с передачей ей параметров <a href="<action>return '/2x2/m4gi_2x2_form.html?session=<fp>&LOWER(SYS(2015))</fp>&uroven=3'</action>">Третий уровень</a> Тег <action></action> может размещаться в теге <fp></fp> <fp> return _m4gi_name+": "+m4gi_money(_m4gi_names.money_)+" "+iif(vartype(post.pwd)="C",[(запомните Ваш пароль! <font color=red size=+1><b>]+post.pwd+[</font>)],"")+; iif(_m4gi_names.money_>0,[<br> <a href="<action>m4gi_newform('\m4gi_magazin.html')</action>">К магазину!</a>],"") </fp> Если реакция размещается внутри тега <fp></fp> и текст реакции состоит из многострочного кода, может понадобиться специальная комбинация {{ для вставки "перехода строки" в коде текста реакции <fp>return iif(_m4gi_type=0,[<p align=right><i><font size=-1><a href="<action>_m4gi_type=1{{_m4gi_name=''</action>">Перейти к добавлению нового пользователя</a></font></i></p>],; [<p align=right><i><font size=-2><br><br><a href="<action>_m4gi_type=0{{_m4gi_name=''</action>">Отказаться от добавления нового пользователя</a></font></i></p>])</fp> А вот если бы реакция НЕ РАЗМЕЩАЛАСЬ в теге <fp></fp>, текст <a href="<action>{{_m4gi_type=0{{_m4gi_name=''</action>">Отказаться от добавления нового пользователя</a> мог БЫ быть несколько другим: <a href="<action> _m4gi_type=0 _m4gi_name='' </action>">Отказаться от добавления нового пользователя</a> Комбинация {{ избавляет от ошибки при выполнении кода в теге <fp></fp> при МНОГОСТРОЧНОМ коде <action></action> Дело в том, что при формировании страницы из gi-формы СНАЧАЛА обрабатываются теги <fp></fp> - т.е. попросту выполняется некий одно- или многострочный FoxPro-код в этих тегах. А так как код реакции <ation></action> ТАК ЖЕ может содержать многострочный код, то БЕЗ {{ возникает "конфликт интересов" ПРИМЕР НЕПРАВИЛЬНОГО написания реакции (в теге <fp></fp>): <fp>return iif(_m4gi_type=0,[<p align=right><i><font size=-1><a href="<action>_m4gi_type=1{{_m4gi_name=''</action>">Перейти к добавлению нового пользователя</a></font></i></p>],; [<p align=right><i><font size=-2><br><br><a href="<action> _m4gi_type=0 _m4gi_name='' </action>">Отказаться от добавления нового пользователя</a></font></i></p>])</fp> ...который, при попытке выполнить его вернет ошибку (можете проверить у себя в окне FoxPro ) --------------------------------------------- Альтернатива <action></action>. Код <action></action> срабатывает при кликах на ссылках или отправкой данных html-формы. После чего идет переформирование текущей страницы или открытие новой. Есть АЛЬТЕРНАТИВНЫЙ способ, который позволит сделать многое прямо с текущей страницей. Для этого используется специальная конструкция <scriptaction></scriptaction> внутри которого размещается код обработки. <a onclick="<scriptaction> wait window "Добрый день! Сегодня "+dtoc(datetime()) nowait </scriptaction>" href="javascript:void(0)">Пример вывода в окне Wait приветствия с текущей датой</a> Еще вариант использования <scriptaction></scriptaction> - в обработке события таймера: (правда В РАБОЧЕЙ СТРАНИЦЕ Я ЭТОТ КОД ЗАКОММЕНТИРОВАЛ!Объяснение почему - чуть ниже) <p align=right>Текущие Дата/время: <b id="timestr"><fp>&datetime()</fp></b></p> <script type="text/javascript"> setInterval(function(){ <scriptaction> local jj jj=ttoc(datetime()) this_form.caption="Кто тут? ("+jj+")" this_form.wb.Document.getElementByID("timestr").innerHtml=jj </scriptaction>; }, 755); </script> Данный пример срабатывает через каждые 755 мс и одновременно меняет заголовок окна и значение элемента с id равном timestr на текущей странице. Обратите внимание - для доступа к caption формы и web-контролу (wb) на ней используется специальный временный объект this_form (а не Thisform) Обратите внимание - в html-странице обязательно должен быть объявлен элемент timestr (это идентификатор позиции, куда будет вставлен результат работы fox-процедуры) Тоже самое, наверное, можно сделать и на чистом Javascript, но тут стоит простейшая задача - показать, что FoxPro-код выполняется ВСЕ ОТЛИЧНО в работе данного кода НО... ПРИ БОЛЬШОЙ НАГРУЗКЕ на процессор setInterval срабатывает ДАЖЕ после перехода на другую страницу. Мало того, это вообще иногда ведет к ошибке javascript. К сожалению, пока победить setInterval мне не удалось. А так как конструкция <scriptaction></scriptaction> применяется при использовании в javascript, необходимо хотя-бы начальное знание об этом javascript. К сожалению, это как раз мой случай - ну не работал я с javascript вплотную. Нужен, видимо, совет эксперта по JavaScript и IE, чтобы НАКОНЕЦ-ТАКИ разобраться, как IE работает с таймером setInterval (если честно, думал, что при открытии новой страницы предудущие события таймера отменяются. Наверное, это все таки не так...) Обобщаю: НЕ РЕКОМЕНДУЕТСЯ использовать <scriptaction></scriptaction> с таймерами. Зато в остальных случаях - пожалуйста. ОЧЕНЬ бы хотелось бы получить примеры работы с javascript от его знатоков. Кстати, на странице forum.foxclub.ru есть пример запуска javascript-функции из FoxPro и обработка результатов этой функции. --------------------------------------------- Размещение <scriptaction></scriptaction> в gi-форме. Нужно понимать, что код <scriptaction></scriptaction> может сработать ТОЛЬКО ПОСЛЕ ЗАГРУЗКИ ВСЕЙ СТРАНИЦЫ. Код javascript, приведенный ниже, создает объект htmlapp (), посредством которого в дальнейшем (после совершения какого-либо события) обрабатывается код FoxPro : <script type="text/javascript"> var htmlapp = null; </script> А вот нижеследующий код вызовет ОШИБКУ: <script language="JavaScript"> document.write(<scriptaction>dtoc(date())</scriptaction>) </script> Ведь здесь на момент выполнения document.write html-страница ЕЩЕ НЕ ЗАГРУЖЕНА! --------------------------------------------- Таймер на FoxPro - гораздо более стабильный таймер. Обычно создается в init gi-формы. Например, следующий код делает то-же самое, что и процедура с setInterval (выше), а именно - через определенный интервал меняет заголовок формы и время на странице: THIS_FORM.AddObject("_timer1","cmoitimer") local stro TEXT TO stro TEXTMERGE NOSHOW if left(this_form.caption,3)=="Кто" && исключение срабатывания на другой форме local jj,zz jj=ttoc(datetime()) this_form.caption="Кто тут? ("+jj+")" zz=This_form.wb.Document.getElementByID("timestr") if not isnull(zz) zz.innerHtml=jj endif endif ENDTEXT this_form._timer1.post=post this_form._timer1.this_form=this_form this_form._timer1.textproc=stro this_form._timer1.interval=100 Данный код - ГОРАЗДО более стабилен в работе. Единственный минус - в следующей открываемой форме необходимо в load (именно в load, а не init) работающий таймер надо удалить (c другой стороны - раз созданный таймер будет работать все время, что иногда может быть и плюсом ). Например, уже после авторизации, в load gi-форме /m4gi_list.html есть код : this_form.RemoveObject("_timer1") который удаляет добавленный ранее таймер. --------------------------------------------- Во внешних процедурах (prg-файлах) ОБЯЗАТЕЛЬНО наличие строки с МИНИМУМОМ двумя параметрами: LPARAMETERS post,this_form Например, в /2x2/prg_m4gi_2x2_prover.prg, кроме основных параметров, есть так же параметры ur и shag, требующиеся для работы именно этой процедуры: LPARAMETERS post,this_form,ur,shag IF VAL(post.proiz)=0 RETURN .T. ENDIF SELECT _m4gi_table_2x2 GO shag REPLACE otvet WITH .T.,proizv WITH VAL(post.proiz),pravilno WITH IIF(mnoj1*mnoj2=VAL(post.proiz),.T.,.F.),time_ with DATETIME() IF RECCOUNT()=shag && пройден m4gi_newform("2x2\m4gi_2x2_rezultat.html?urrez="+ALLTRIM(STR(ur))+"&shagrez="+ALLTRIM(STR(shag))) ENDIF RETURN .T. --------------------------------------------- Страница HTML НЕ ДОЛЖНА реагировать на вторую (неосновную) кнопку мыши, так как все действия с формой ведутся ТОЛЬКО с помощью основной кнопки. В BODY html-страницы необходимо внести код oncontextmenu="return false", например: <BODY oncontextmenu="return false"> Если этого не сделать - у пользователя "возникнут" вопросы (контекстное меню не контролируется) --------------------------------------------- Результат реакции <action></action> может быть различных типов: 1. При C(символьное) - подразумевается, что это адрес gi-формы или html-страницы - открытие "результата", т.е. gi-формы или страницы html в том же окне. По сути - переход к нужной форме. 2. При L(логическое) - .T. - переформирование и обновление текущей страницы (по умолчанию, .t. возвращается, если нет в коде нет оператора Return со значением) Обновление gi-формы требуется после выполнения каких-либо действий, например, после окончания редактирования элемента. 3. При L(логическое) - .F. - ничего не переформировывается. --------------------------------------------- Встроенные функции для работы каталогами и файлами в рабочем каталоге m4gi_file(file) - возвращает .t. при существовании файла. m4gi_file_path(file) - возвращает полный путь файла из краткого (это требуется, например, для создания временных таблиц). m4gi_file_path("\2x2\metka.gif") m4gi_folder(folder) - возвращает .t. при существовании каталога. m4gi_folder(folder,type)- при type=.t. - возвращает .t., если каталог существует или каталог был успешно создан и существует. функция создает ТОЛЬКО каталоги, относительные к рабочему m4gi_folder("\3x3",.t.) будет .t. и будет создан подкаталог 3x3 в рабочем каталоге m4gi_folder("\pr\tk\sd",.t.) -> создается (если его нет) каталог в рабочем каталоге Функция m4gi_folder - удобный способ для быстрого создания дерева каталогов со всеми ветками. --------------------------------------------- Встроенные функции для работы c каталогами и файлами в каталоге запуска. Данные функции работают ИМЕННО с каталогом ЗАПУСКА. Сделано это для того, что-бы, например, разные пользователи с расшаренного ресурса обращались к одной и той же таблице. Или, например, различные приложения работали с теми же таблицами или файлами. m4gi_file_default(file) - возвращает .t. при существовании файла. m4gi_file_path_default(file) - возвращает полный путь файла из краткого. Например, при каталоге запуска c:\m4gi результатом работы функции m4gi_file_path_default("\2x2\metka.gif") будет c:\m4gi\2x2\metka.gif m4gi_folder_default(folder) - возвращает .t. при существовании каталога. m4gi_folder_default(folder,type)- при type=.t. - возвращает .t., если каталог существует или каталог был успешно создан и существует. функция создает ТОЛЬКО каталоги, относительные к главному например, при каталоге запуска c:\m4gi результатом работы функции m4gi_folder_default("\3x3",.t.) будет .t. и будет создан каталог c:\m4gi\3x3 m4gi_folder_default("\pr\tk\sd",.t.) -> создается (если его нет) каталог c:\m4gi\pr\tk\sd Функция m4gi_folder - удобный способ для быстрого создания дерева каталогов, вне зависимости, существуют или нет ветки каталогов. --------------------------------------------- Прочие функции m4gi_newform(m4gi_form) - открытие модальной gi-формы в НОВОМ окне (т.е. старое не закрывается). например, открытие формы в новом окне с передачей ей параметра: m4gi_newform("\m4gi_error.html?texterror=Неправильно введен пароль, либо пользователь <font color%3Dred>"+ALLTRIM(post.text_name)+"</font> не найден!") m4gi_money(money) - возращает результат в виде html-кода в стиле WarCraft-е, т.е. в виде количества золотых, серебрянных и медных монет. m4gi_money(money,img) - задается другой рисунок для отображения результата. если img - пустой, по умолчанию будет 3 рисунка 1_money.gif 2_money.gif 3_money.gif с путями к рабочему каталогу При задании, например, m4gi_money(10395,"graf.jpg") функция вернет html-код с рисунками: 1_graf.jpg 2_graf.jpg 3_graf.jpg с путями к рабочему каталогу m4gi_money(money,img,gr1,gr2,gr3) gr1,gr2,gr3 - задает название для рисунков (этот текст будет появляться при наведении мышкой). Если gr1,gr2,gr3 пустые - по умолчанию gr1="золото",gr2="серебро",gr3="медь" m4gi_exec(path_file,post,this_form,par1,par2,par3,par4,par5) - запуск процедуры с параметрами. Применяется, для запуска процедур, находящихся в рабочем каталоге, например, m4gi_exec('/2x2/prg_m4gi_2x2_prover.prg',post,this_form,1,2) запустит процедуру prg_m4gi_2x2_prover.prg в подкаталоге 2x2 рабочего каталога и передаст ее параметры post, this_form, 1, 2 m4gi_exec('/prg_m4gi_avtoriz.prg',post,this_form) запуск процедуры, находящейся в корне рабочего каталога m4gi_iconnected() - при .t. - доступ к Интернет существует. Функцию удобно использовать при формировании gi-формы в зависимости от наличия Интернет - формируется тот или иной код страницы. m4gi_unzip("file.zip") - распаковать file.zip (БЕЗ УКАЗАНИЯ ПОЛНОГО ПУТИ!) в папку Рабочего каталога m4gi_unzip_file_to_folder("file.zip","c:\m4gi\") - распаковать file.zip (С ПОЛНЫМ УКАЗАНИЕМ ПУТИ!) в папку c:\m4gi\ m4gi_set_inner(this_form,element,value) - функция замены значения элемента (element) HTML новым значением (value) В случае невозможности замены (нет такого элемента) возвращает Null m4gi_set_inner(this_form,"timestr",ttoc(datetime())) m4gi_get_inner(this_form,element) - получение значения элемента (element) HTML В случае невозможности получения значения (нет такого элемента) возвращает Null wait window m4gi_get_inner(this_form,"timestr") nowait --------------------------------------------- ВАЖНО!Краткая сводка: I. Имя gi-формы должно начинаться с m4gi_ - иначе страница просто не будет обрабатываться. II. <!--m4giproperties --> Даже если ничего не собираетесь обрабатывать при загрузке - данная конструкция все равно ДОЛЖНА НАХОДИТЬСЯ в HTML-файле! Иначе - страница не будет обрабатываться. III. <script type="text/javascript"> var htmlapp = null; </script> Конструкция объявляет переменную htmlapp, к которой в дальнейшем может быть обращение (например, для замены значения HTML-элемента средствами FoxPro). Данная конструкция ДОЛЖНА НАХОДИТЬСЯ в HTML-файле в любом случае! IV. <body oncontextmenu="return false"> Данная кострукция запрещает вызов контекстного меню (что изначально отсекает массу проблем). Если хотите получить неудобные вопросы со стороны пользователя - можете ее не использовать V. Если в gi-форме применяется <form></form> , ОБЯЗАТЕЛЬНО должен быть method="post" - иначе, данные не будут передаваться. VI. Если в теле <fp></fp> находится многострочный текст <action></action> или <scriptaction></scriptaction> - ОБЯЗАТЕЛЬНО в теле <action> или <scriptaction> замените перевод строки на комбинацию {{ Иначе - в процессе обработки кода <fp></fp> получите ошибку. Пример правильного применения: <fp>return iif(_m4gi_type=0,[<p align=right><i><font size=-1><a href="<action>_m4gi_type=1{{_m4gi_name=''</action>">Перейти к добавлению нового пользователя</a></font></i></p>],; [<p align=right><i><font size=-2><br><br><a href="<action>_m4gi_type=0{{_m4gi_name=''</action>">Отказаться от добавления нового пользователя</a></font></i></p>])</fp> VII. ВСЕГДА рекомендуется записывать обращение по путям, начиная с / или \, т.е. с начального каталога. Для чего - сберечь себе нервы. Примеры: m4gi_exec('/2x2/prg_m4gi_2x2_prover.prg',post,this_form,1,2) m4gi_file_path('\2x2\metka.gif') <a href="<action>m4gi_newform('\m4gi_magazin.html')</action>">К магазину!</a> VIII. Старайтесь оставлять двойные кавычки "" для html, ограничивая ими href(ссылка), action(html-форма) или код javascript. При написании кода используйте '' или []. Для чего - сберечь себе нервы (хотя, признаюсь, сам это правило иногда не соблюдаю). Примеры: <form name="main_form" id="main_form_id1" method="post" action="<action>return m4gi_exec('/prg_m4gi_avtoriz.prg',post,this_form)</action>" onsubmit="return false;"> <a href="<action>m4gi_newform('\m4gi_magazin.html')</action>">К магазину!</a> <a onclick="<scriptaction>wait window 'Добрый день! Сегодня '+dtoc(datetime()) nowait</scriptaction>" href="javascript:void(0)">Пример вывода в окне Wait приветствия с текущей датой</a> IX. РЕКОМЕНДУЕТСЯ закрывать (если, конечно, есть такая необходимость) текущую форму ТОЛЬКО коммандой this_form.close --------------------------------------------- ПРИМЕР ТИПИЧНОЙ gi-формы - \m4gi_start.html - авторизация на <form></form> с таймером отображения текущего времени (реализован на FoxPro): <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd"> <HTML><HEAD> <META http-equiv=Content-Type content="text/html; charset=windows-1251"> <title>Страница Интерфейса</title> <META HTTP-EQUIV="Keywords" CONTENT="Генератор Интерфейса"> <META name="Author" content="Igor Croschin"> <META name=keywords content=""> <META name=description content=""> <script type="text/javascript"> var htmlapp = null; </script> <!--m4giproperties <load> this_form.caption="Кто тут?" IF VARTYPE(_m4gi_name)<>"C" PUBLIC _m4gi_name _m4gi_name="" && ""-никто не выбран, иначе - будет проставлено в поле имени ENDIF IF VARTYPE(_m4gi_type)<>"N" PUBLIC _m4gi_type _m4gi_type=0 && 0-предполагается авторизация; 1-предполагается добавление ENDIF if not used("_m4gi_korzina") select 0 create cursor _m4gi_korzina (id_ n(15),name_ c(50),id_predmet n(15)) endif if not used("_m4gi_magazin") local ims ims = m4gi_file_path_default("\_m4gi_magazin.dbf") if m4gi_file(ims) select 0 use (ims) else select 0 create table (ims) (id_predmet n(15),kratkoe c(200), polnoe m, cena n(15), img_ c(200)) use (ims) endif endif if not used("_m4gi_trofei") ims = m4gi_file_path_default("\_m4gi_trofei.dbf") if m4gi_file(ims) select 0 use (ims) else select 0 create table (ims) (id_ n(15),id_predmet n(15),date_ t) use (ims) endif endif select * from _m4gi_magazin into cursor _m4gi_magazin_temp order by cena IF USED("_m4gi_names") SELECT _m4gi_names USE ENDIF IF m4gi_file_default("_m4gi_names.dbf") SELECT 0 USE (m4gi_file_path_default("_m4gi_names.dbf")) ELSE SELECT 0 CREATE TABLE m4gi_file_path_default("_m4gi_names.dbf") (id_ N(15), name_ c(50), pwd_ c(20), money_ n(15)) ENDIF </load> <init> THIS_FORM.AddObject("_timer1","cmoitimer") local stro TEXT TO stro TEXTMERGE NOSHOW if left(this_form.caption,3)=="Кто" && срабатывание только на этой форме local jj,zz jj=ttoc(datetime()) this_form.caption="Кто тут? ("+jj+")" m4gi_set_inner(this_form,"timestr",jj) else this_form._timer1.enabled=.f. && таймер работает только при .t. endif ENDTEXT this_form._timer1.textproc=stro this_form._timer1.post=post this_form._timer1.this_form=this_form this_form._timer1.interval=100 </init> --> </HEAD> <body oncontextmenu="return false"> <br> <SCRIPT LANGUAGE="JavaScript" SRC="fly.js"> </script> <p align=right>Текущие Дата/время: <b id="timestr"><fp>&datetime()</fp></b></p> <!-- <script type="text/javascript"> setInterval(function(){ <scriptaction> local jj jj=ttoc(datetime()) this_form.caption="Кто тут? ("+jj+")" This_form.wb.Document.getElementByID("timestr").innerHtml=jj </scriptaction>; }, 755); </script> --> <br> <form name="main_form" id="main_form_id1" method="post" action="<action>return m4gi_exec('/prg_m4gi_avtoriz.prg',post,this_form)</action>" onsubmit="return false;"> <fp> LOCAL stro stro="" DO CASE CASE _m4gi_type=0 TEXT TO stro TEXTMERGE NOSHOW Необходимо авторизоваться (что-бы понять, а кто, собственно, здесь находится).<br><br> <br>Введите имя: <input type="text" name="text_name" id="text_id1" value="<<_m4gi_name>>" /> <br>Введите пароль: <input type="password" name="text_pwd" id="text_id2" value="" /> ENDTEXT CASE _m4gi_type=1 TEXT TO stro TEXTMERGE NOSHOW Добавление нового пользователя.<br><br> <br>Введите имя: <input type="text" name="text_name" id="text_id3" value="<<_m4gi_name>>" /> <br>Отнеситесь к этому внимательно! Восстановление пароля "невозможно"!<br><br>Введите пароль: <input type="password" name="text_pwd1" id="text_id4" value="" /> <br>Введите пароль еще раз (для проверки): <input type="password" name="text_pwd2" id="text_id5" value="" /> ENDTEXT ENDCASE return stro </fp> </form> <input type="button" value="<fp>&iif(_m4gi_type=0,"Войти","Добавить и войти")</fp>" onclick="document.forms['main_form'].submit();"> <fp>&iif(_m4gi_type=0,[<p align=right><i><font size=-1><a href="<action>_m4gi_type=1{{_m4gi_name=''</action>">Перейти к добавлению нового пользователя</a></font></i></p>],; [<p align=right><i><font size=-2><br><br><a href="<action>_m4gi_type=0{{_m4gi_name=''</action>">Отказаться от добавления нового пользователя</a></font></i></p>])</fp> <br> <a onclick="<scriptaction> wait window "Добрый день! Сегодня "+dtoc(datetime()) nowait </scriptaction>" href="javascript:void(0)">Кликните! Пример вывода в окне Wait приветствия с текущей датой</a> </body> </html> --------------------------------------------- Исправлено 1 раз(а). Последнее : maple4, 08.12.10 11:59 |
Re: Генератор Интерфейса (с использованием web-контрола) | |
---|---|
maple4 Автор Сообщений: 210 Откуда: Москва Дата регистрации: 26.10.2007 |
Обсуждения, как обычно в этом разделе, не получилось.
Лично я для себя тему с применением web-контрола закрыл - выжал, по моему, все что мог, попутно наступив на все возможные грабли. Естественно, через это (грабли) должен пройти каждый, но попытаюсь описать то, с чем пришлось столкнуться (все было РЕШЕНО!): I. 1. Обработка адреса в ссылке и web-форме. Проблема начинается, если в адресе присутствуют буквы национального алфавита, спецсимволы и пробел. Предварительная кодировка (в esc-последовательность) - только себя путать + страдает удобочитаемость кода. 2. Передача параметров. Это можно сделать как ссылкой, так и формой <form></form> (при этом не забыть, что в <form> method="post"). Если в параметрах есть буквы национального алфавита, спецсимволы и пробел - тут же проблема с адресом. При клике по ссылке, сформированной с параметрами - при обработке адреса параметры не обрабатываются, если страница находится не в текущем каталоге - нет объяснения. 4. Многострочный текст кода FoxPro. Если по клику на ссылке запускается функция - вроде бы никаких проблем нет. Ну а если текст обработки клика состоит из двух и более строк? Нужно так же учесть, что есть ограничение на длину выражения в самом <a href=""> - длина почему-то меньше заявленной для IE. РЕШЕНИЕ ВСЕЙ ЭТОЙ группы проблем - при клике по ссылке или кнопке запускается функция (а уже в ней - ведется обработка) , которая и возвращает правильный адрес. Например, вместо <br><a href="m4gi_2x2_form.html?session=_dsddg1234&igrok=Валера&uroven=1">I</a> НАДО записать <br><a href="<action>return '/2x2/m4gi_2x2_form.html?session=_dsddg1234&igrok=Валера&uroven=1'</action>">I</a> и уже во время формирования конструкция <action>....</action> будет АВТОМАТИЧЕСКИ заменена строкой VFP:///return m4gi_progar(post,this_form,1) или, полностью: <br><a href="VFP:///return m4gi_progar(post,this_form,1)">I</a> ОБРАТИТЕ ВНИМАНИЕ - в строке НЕТ упоминания о странице html,параметрах и коде FoxPro , что СРАЗУ снимает кучу проблем, например, с той же кодировкой национального алфавита, спецсимволов и пробела. II. Код FoxPro в коде Javascript. В коде JavaScript можно вставить код FoxPro, результат которого может быть обработан далее тем же javascript. Во время формирования страницы .... <script type="text/javascript"> setInterval(function(){ <scriptaction> local jj jj=ttoc(datetime()) this_form.caption="Кто тут? ("+jj+")" This_form.wb.Document.getElementByID("timestr").innerHtml=jj </scriptaction>; }, 755); </script> ... следующая конструкция <scriptaction>... </scriptaction> будет автоматически заменена на функцию javascript, которая, в свою очередь, запустит на выполнение код FoxPro: <script type="text/javascript"> setInterval(function(){ htmlapp.scriptaction(1); }, 755); </script> Почему может потребоваться код FoxPro в Javascript? Самое главное: Используя FoxPro Вы НИ В ЧЕМ себя не ограничиваете - полная свобода действий, в отличие от стандарта JavaScript. И сразу немного дегтя - НЕ рекомендуется использовать setInterval вместе с FoxPro (для этого лучше использовать Timer FoxPro в <init></init> формы). this_form.AddObject("_timer1","cmoitimer") local stro TEXT TO stro TEXTMERGE NOSHOW if left(this_form.caption,3)=="Кто" && срабатывание только на этой форме local jj,zz jj=ttoc(datetime()) this_form.caption="Кто тут? ("+jj+")" m4gi_set_inner(this_form,"timestr",jj) else this_form._timer1.enabled=.f. && таймер работает только при .t. endif ENDTEXT this_form._timer1.textproc=stro this_form._timer1.post=post this_form._timer1.this_form=this_form this_form._timer1.interval=100 Именно для использования <action></action> и <scriptaction></scriptaction> требовался запрет (по Backspace и Alt+влево) перехода на предыдущую страницу. P.S. Всех с Cataclyzm-ой |
Re: Web-интерфейс для FoxPro-программы | |
---|---|
maple4 Автор Сообщений: 210 Откуда: Москва Дата регистрации: 26.10.2007 |
Обновился Генератор Интерфейса.
Страница проекта: www.maple4.ru Дистрибутив: www.maple4.ru ~650 Кб. Дистрибутив содержит prg-файлы и формы. Для запуска требуется установленный FoxPro 9! Рекомендую ИЗ ОКНА FoxPro запустить готовый m4gi.exe или скомпилировать его из проекта. Что появилось/изменилось: I. Теперь тестовый проект (gi-формы) использует стили. Соответственно, и вид - совершенно другой. Обратите внимание - для игры 2x2 используется свой особенный стиль. II. Появилась возможность добавлять текстовые многострочные сообщения, причем текст редактируется в WYSIWYG-режиме (т.е. например, как во FrontPage. Или Word-e). Есть кнопки управления начертанием шрифта, управления цветом и фоном, видом нумерованного списка. Остальные - не рассматривал, но, при необходимости, можно добавить нужные кнопки с нужной реакцией (поиск в google по "execCommand"). Код - смесь JavaScript, FoxPro (в конструкции <action></action>, отвечающей за реакцию при добавлении сообщения. Обратите внимание - при попытке добавить пустое сообщение "вылезет" окно с предупреждением) и языка разметки HTML:
III. Добавил страницу отображения всех сообщений с возможностью листания (по 10 сообщений на страницу). Реализуется кодом FoxPro (в конструкциях <fp>...</fp>) и языком разметки HTML (сначала выводится навигатор по страницам, потом - список сообщений на страницу в HTML-таблице):
IV. Добавил страницу с отображением курсов валют на текущее число (cbr.ru) и событий за число в истории (wikipedia.org) По сути - грабберы, т.е. нет никаких xml-файлов (но, например, для cbr.ru такой файл, скорее всего, есть). Например, код для считывания курсов прямо со страницы сайта cbr.ru.
Исправлено 1 раз(а). Последнее : maple4, 24.12.10 15:12 |
© 2000-2024 Fox Club  |