diff --git a/Blog/Extensions/FormProcessors.hs b/Blog/Extensions/FormProcessors.hs
index 90678b4..698d1dc 100644
--- a/Blog/Extensions/FormProcessors.hs
+++ b/Blog/Extensions/FormProcessors.hs
@@ -6,6 +6,6 @@ import Framework.Forms.Types
import Framework.Modules.TextCaptcha.FormProcessors
-- | These functions may modify each Form.
-formProcessors :: FormsPlugins
+formProcessors :: FormProcessors
formProcessors = [addCaptcha ["commentform"]]
diff --git a/Framework/Forms/ModelForm.hs b/Framework/Forms/ModelForm.hs
index 84f1765..75789b5 100644
--- a/Framework/Forms/ModelForm.hs
+++ b/Framework/Forms/ModelForm.hs
@@ -9,6 +9,7 @@ import Framework.Forms.Validators
import Framework.Forms.HTML
import Framework.ORM
+-- | Generate a Form from Model
modelForm :: Model -> Form
modelForm model = Form {
formName = (mName model)++"form",
@@ -31,5 +32,6 @@ mf2ff' :: String -> ColumnType -> FormField
mf2ff' name IntegerColumn = Field name "" inputbox noValidate
mf2ff' name StringColumn = Field name "" inputbox noValidate
+-- | Add a list of fields into form
addFields :: Form -> [FormField] -> Form
form `addFields` lst = form {fFields = (fFields form)++lst}
diff --git a/Framework/Forms/Types.hs b/Framework/Forms/Types.hs
index 2f90dec..0ab8f7e 100644
--- a/Framework/Forms/Types.hs
+++ b/Framework/Forms/Types.hs
@@ -5,7 +5,7 @@ module Framework.Forms.Types
HTMLForm (..),
HTMLTag (..), HTML,
Widget (..),
- FormsPlugins, FormController,
+ FormProcessors, FormController,
FormValidator, FieldValidator
) where
@@ -17,7 +17,7 @@ import Framework.Forms.HTMLTypes
type FormController = AController Form
-- | Form plugin transforms a Form
-type FormsPlugins = [Form -> FormController]
+type FormProcessors = [Form -> FormController]
-- | Form validator takes request and returns either list of erroneus filled field or filled Model
type FormValidator = HttpRequest -> Either [String] Model
diff --git a/Framework/Modules/TextCaptcha/FormProcessors.hs b/Framework/Modules/TextCaptcha/FormProcessors.hs
index d0a1a26..c932645 100644
--- a/Framework/Modules/TextCaptcha/FormProcessors.hs
+++ b/Framework/Modules/TextCaptcha/FormProcessors.hs
@@ -1,5 +1,8 @@
{-# LANGUAGE PatternGuards, TypeFamilies #-}
-module Framework.Modules.TextCaptcha.FormProcessors where
+module Framework.Modules.TextCaptcha.FormProcessors
+ (addCaptcha,
+ validateCaptcha
+ ) where
import Debug.Trace
@@ -46,6 +49,7 @@ instance Widget TextCaptcha where
wRead = read
+-- | Generate a random captcha
randomCaptcha :: IO TextCaptcha
randomCaptcha = do
x <- getStdRandom (randomR (-50,50))
@@ -60,7 +64,7 @@ isNum s = (not $ null s) && ((head s) `elem` "-0123456789") && (all isDigit (tai
validateCaptcha :: FieldValidator
validateCaptcha rq name str =
- if (trace ("S:"++str) val) == (trace (show targetval) targetval)
+ if val == targetval
then Right str
else Left name
where
diff --git a/Framework/ORM/Models.hs b/Framework/ORM/Models.hs
index bab1a6a..7c9917f 100644
--- a/Framework/ORM/Models.hs
+++ b/Framework/ORM/Models.hs
@@ -17,6 +17,7 @@ import Database.HDBC (SqlValue(..), fromSql)
import Framework.Types
import Framework.ORM.Types
+emptyModel :: Model
emptyModel = Model {
mName = "default",
mTable = "default",
diff --git a/README.ru b/README.ru
index fa61350..bd25b87 100644
--- a/README.ru
+++ b/README.ru
@@ -54,9 +54,9 @@ allposts. А конфигурация
"blog" // "archive" --> archive
-означает, что URL, начинающиеся с /blog/archive/,
-обрабатывает контроллер archive. Оператор <|> комбинирует конфигурации по
-принципу "если не первое, то второе". Например,
+означает, что URL, начинающиеся с /blog/archive/, обрабатывает контроллер
+archive. Оператор <|> комбинирует конфигурации по принципу "если не первое, то
+второе". Например,
urlconf = "blog" // "archive" --> archive
<|> "blog" --> allposts
@@ -68,6 +68,86 @@ allposts. А конфигурация
со следующими правилами в конфигурации. Если ни одно правило не подошло (или
все подходящие контроллеры отвергли этот url), будет порождена ошибка HTTP 404.
+## Модели
+
+Модели представляются экземплярами типа Model. Для модели нужно указать имя и
+имя соответствующей таблицы в БД (если нужно делать по ней запросы). Кроме
+того, модель должна содержать список полей. Поля моделей представляются типом
+ModelField. При описании используются следующие конструкторы данных:
+
+ name ::: type -- поле с именем name и типом type
+ поле `ValidateBy` функция -- так можно указать функцию для валидации этого
+ поля в формах
+ поле `UsingWidget` виджет -- так можно указать, каким виджетом отображать это
+ поле в формах
+
+## Формы
+
+Формы представляются экземплярами типа Form. Для формы указывается имя и
+модель, представляющую данные в этой форме. Кроме того, указывается список
+полей. Поля представляются конструктором данных Field:
+
+ Field имя подпись виджет валидатор
+
+Можно автоматически получать формы из моделей, для этого служит функция
+modelForm, определённая в модуле Framework.Forms.ModelForm. Она использует
+валидаторы и виджеты, заданные в модели при помощи конструкторов ValidateBy и
+UsingWidget.
+
+## Шаблоны
+
+Синтаксис шаблонов основан на синтаксисе шаблонов Django. Шаблон может включать
+переменные в виде {{variable}}. Можно к переменным применять функции
+специального типа (см. ниже): {{function variable}}. Кроме того, поддерживаются
+следующие операторы:
+
+{%if variable%} --- вариант: {%if function variable%}
+...
+{%else%}
+...
+{%endif%}
+
+(часть else, как обычно, необязательна)
+
+{%for var in list%}
+...
+{%endfor%}
+(внутри цикла появляется дополнительная переменная {{it}}, содержащая номер
+текущей итерации).
+
+{%include filename%}
+(включение другого шаблона)
+
+{%includevar var%}
+(включается шаблон, имя которого содержится в переменной var).
+
+Основная функция, служащая для рендеринга шаблонов - это render. Она принимает
+два параметра: имя шаблона и контекст. Контекст - это список пар (имя
+переменной, значение). Значения для передачи в шаблон оборачиваются в
+контейнерный тип TContainer с помощью конструктора C.
+
+Однако в контроллерах удобнее использовать функции семейства renderToResponse*.
+Они возвращают не HTML, а сразу готовый HttpResponse.
+
+Функции, применяемые к переменным в шаблонах, должны иметь полиморфный тип
+(TemplateOne a) => a -> String (для функций, применяемых в теге if --
+соответственно, a -> Bool). Эти функции для моделей можно определять с помощью
+функций transformInt, transformString, transformBool. Они принимают номер поля
+данного типа (IntegerColumn,StringColumn, BoolColumn соответственно) в модели,
+и функцию, обрабатывающую значение этого типа, а возвращают функцию, подходящую
+для использования в шаблонах. Примеры для функций-аксессоров см. в модуле
+Models приложения Blog.
+
+В модуле Framework.TEngine.TemplateFuncs определены некоторые часто
+используемые функции для использования в шаблонах.
+
+"Атомарные" значения (т.е. не модели, а числа, строки итп) считаются имеющими
+единственное поле соответствующего типа.
+
+Шаблоны описываются в отдельных файлах, но при сборке приложения обрабатываются
+утилитой TemplateGen, которая генерирует модуль Framework.TEngine.Templates (в
+котором собственно и определяется функция render).
+
## Контроллеры
Контроллеры приложения (и некоторые другие части) выполняются в монаде
diff --git a/TODO b/TODO
index 01873a8..9194e30 100644
--- a/TODO
+++ b/TODO
@@ -1,11 +1,12 @@
TODO
- * (?) Генерация структуры Form по Model (с возможностью переопределить, или просто не использовать);
- * Удобные средства расширения форм (в т.ч. и для использования в Form processors);
+ * [PARTIALLY DONE] Удобные средства расширения форм (в т.ч. и для использования в Form processors);
+ * Больше виджетов для форм;
* Средства создания "мастеров";
* (?) Автоматические CRUD-контроллеры;
* Человеческая обработка завершения программы;
* Все параметры, которые сейчас hard-coded, брать из конфига;
+ * (?) Полу-автоматическая интернационализация с помощью какого-л. Middleware;
* [PARTIALLY DONE] Более высокоуровневый интерфейс для кэша - чтоб было легко закэшировать результат всей функции;
* [PARTIALLY DONE] Соответственно, простые средства для инвалидации кэша;
* [PARTIALLY DONE] Более продвинутые и высокоуровневые функции генерации SQL;
@@ -14,6 +15,7 @@ TODO
* (!) Документация ко всей этой красоте.
* Протестировать поддержку PUT web-сервером;
+ * [DONE] Генерация структуры Form по Model (с возможностью переопределить, или просто не использовать);
* [DONE] Бэкенд для MySQL;
* [DONE] Чтение конфига из файла либо удобный EDSL для конфига;
* [DONE] Перенести текущий правленный Network.Shed.Httpd в дерево проекта (написать свой?);