В рамках сооружения нового слоя модели для alterator. Сейчас идёт работа
над "языком форм" alterator. У нас будет использоваться классическая
модель MVC. Кстати сразу, если кто знает ещё какие хорошие модели - шлите
урлы, попробуем и их на зуб.
Задачи которые мы хотим решить:
1. Облегчить пользователю соединение между слоем backend и слоем ui.
Это у нас будет обеспечиваться за счёт предоставление большого числа
готовых view и controller'ов.
2. Обеспечить возможность сотворения формы из отдельных фрагментов,
инсталлируемых по мере необходимости. (user: ldap + postfix + samba + ...)
1. Создание view.
Каждый view есть некий "виджет" со стандартным набором атрибутов.
Для view поля это: field-name,field-value,field-data. Первые сами
говорят за себя, последний атрибут - доп. данные , например список для
combobox.
Виджет может быть реализован на браузере интерфейса, а может быть
создан из готовых кусочков, вот например так как показано ниже:
----------------
(document:surround "/std/base")
(document:envelop with-proxy-attributes
((field-name ((proxy-set self value) (lbl text value))
((proxy-get self value) (lbl text)))
(field-data ((proxy-set self value) #f);;ignore
((proxy-get self) #f));;ignore
(field-value ((proxy-set self value) (txt text value))
((proxy-get self) (txt text)))))
type "hbox"
layout-policy 100 -1
(document:id lbl (label "" layout-policy 50 -1))
(document:id txt (edit "" layout-policy -2 -1))
----------------
2. Создание контроллера для view.
Контроллер есть объект (см. соотв. документацию на alterator, про объектную
систему), со стандартными
методами.
Например для контроллера поля это есть: field-update, field-commit.
Для контроллера формы это есть: form-update, form-commit.
3. Соединяем это всё вместе. В alterator мы можем позволить себе при
создании UI "склеивать" view с их контролерами. Поэтому после конструирования
мы работаем с этим конгломератом.
Этот комментарий для понимания кода, простому пользователю можно с этим даже не
заморачиваться.
4. Простейший пример формы:
4.1 Контроллер формы simple-object - работает с экземпляром того или иного
класса. В данном случае с экземплярами класса "/local_users".
-----
(define (simple-object class)
(object #f
((form-update self name)
(define-operation list-subwidgets)
(define-operation field-update #f)
(let ((cmd (woo-read-first (string-append class "/" name))))
(for-each (lambda(f) (field-update f cmd))
(list-subwidgets self))))
((form-commit self name)
(define-operation list-subwidgets)
(define-operation field-commit '())
(apply woo-write (string-append class "/" name)
(append-map (lambda(f) (field-commit f))
(list-subwidgets self))))))
-----
(Note: мусор в виде define-operation может быть вынесен в стандартные
библиотеки)
4.1 Контроллер поля simple-property - работает индивидуально с конкретным
свойством того или иного экземпляра класса.
---
(define (simple-property property)
(object #f
((field-update self obj)
(self field-value (woo-get-option obj property)))
((field-commit self)
(list property (self field-value)))))
---
4.2 Каждое поле создаётся командой:
(field "url-view" "name" controller <другие параметры к view>)
Где url-view - урл документа, содержащего описание view данного поля.
Для простых пользователей планируется заготовить набор стандартных view, и
контроллеров.
Пример:
----------
(field '/fields/text "My property (simple-property 'property))
----------
4.3 Каждая форма создаётся командой:
(form "url-view" "name" controller <поля и другие параметры к view>)
Например:
----------
(form '/fields/prop-list "My object" (simple-object '/some_users)
layout-policy 100 30
(field ... )
...)
----------
4.4 Ниже приведён полный пример формы, для пользователей.
Обратите внимание, что кнопки управления вынесены из view по имени
"/std/vbox" (стандартная вертикальная группа виджетов), но ничто не препятсвует
сделать управление прямо внутри view. Зато можно посмотреть на то как при
желании
можно обращаться с наружи к этому конгломерату "view + controller".
Также обратите внимание. что при необходимости можно смешивать поля и
другие виджеты произвольной природы.
---------------
(document:id f1
(form "/std/vbox" "User's properties" (simple-object
"/local_users")
layout-policy 100 -1
(field "/b" "Comment:" (simple-property 'gecos))
(label "Not a field in the form")
(field "/b" "Home:" (simple-property 'home))
(field "/b" "Shell:" (simple-property 'shell))))
(hbox
(document:id username (edit "<username>"))
(button "Update"
(when clicked
(define-operation form-update)
(form-update f1 (username text))))
(button "Commit"
(when clicked
(define-operation form-commit)
(form-commit f1 (username text)))))
--------------
В аттаче приложены файлы, чтобы можно было запустить этот пример в своём
alterator.
--
С наилучшими пожеланиями
Станислав Иевлев.
(document:surround "/std/base")
(document:envelop with-attributes
(field-name field-value field-data
form-name))
(define (field url name controller . args)
(let ((widget (document:subdocument url)))
(apply widget field-name name args)
(join widget
controller
(object #f ((extract-widget self) widget)))))
(define (form url name controller . args)
(let ((widget (document:subdocument url)))
(apply widget form-name name args)
(join widget
controller
(object #f ((extract-widget self) widget)))))
(define (simple-property property)
(object #f
((field-update self obj)
(self field-value (woo-get-option obj property)))
((field-commit self)
(list property (self field-value)))))
(define (simple-object class)
(object #f
((form-update self name)
(define-operation list-subwidgets)
(define-operation field-update #f)
(let ((cmd (woo-read-first (string-append class "/" name))))
(for-each (lambda(f) (field-update f cmd))
(list-subwidgets self))))
((form-commit self name)
(define-operation list-subwidgets)
(define-operation field-commit '())
(apply woo-write (string-append class "/" name)
(append-map (lambda(f) (field-commit f))
(list-subwidgets self))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(document:id f1
(form "/std/vbox" "User's properties" (simple-object
"/local_users")
layout-policy 100 -1
;;(document:insert-all '/lll)
(field "/b" "Comment:" (simple-property 'gecos))
(label "Not a field in the form")
(field "/b" "Home:" (simple-property 'home))
(field "/b" "Shell:" (simple-property 'shell))))
(hbox
(document:id username (edit "<username>"))
(button "Update"
(when clicked
(define-operation form-update)
(form-update f1 (username text))))
(button "Commit"
(when clicked
(define-operation form-commit)
(form-commit f1 (username text)))))
(document:surround "/std/base")
(document:envelop with-proxy-attributes
((field-name ((proxy-set self value) (lbl text value))
((proxy-get self value) (lbl text)))
(field-data ((proxy-set self value) #f);;ignore
((proxy-get self) #f));;ignore
(field-value ((proxy-set self value) (txt text value))
((proxy-get self) (txt text)))))
type "hbox"
layout-policy 100 -1
(document:id lbl (label "" layout-policy 50 -1))
(document:id txt (edit "" layout-policy -2 -1))
_______________________________________________
Devel-conf mailing list
[email protected]
https://lists.altlinux.org/mailman/listinfo/devel-conf