Author: achiumenti Date: Tue Feb 19 06:24:12 2008 New Revision: 13
Modified: trunk/main/claw-core/src/components.lisp trunk/main/claw-core/src/misc.lisp trunk/main/claw-core/src/packages.lisp trunk/main/claw-core/src/tags.lisp trunk/main/claw-core/tests/test1.lisp Log: added beginning of validation support. added method page-current-component to page
Modified: trunk/main/claw-core/src/components.lisp ============================================================================== --- trunk/main/claw-core/src/components.lisp (original) +++ trunk/main/claw-core/src/components.lisp Tue Feb 19 06:24:12 2008 @@ -40,33 +40,41 @@ (:documentation "This component render as a FORM tag class, but it is aware of the request cycle and is able to fire an action on rewind"))
-(defmethod cform-rewinding-p ((obj cform) (pobj page)) - (string= (htcomponent-client-id obj) - (page-req-parameter pobj *rewind-parameter*))) - -(defmethod wcomponent-parameters ((o cform)) - (list :id :required :action nil)) - -(defmethod wcomponent-template((o cform)) - (let ((client-id (htcomponent-client-id o))) +(defmethod cform-rewinding-p ((cform cform) (page page)) + (string= (htcomponent-client-id cform) + (page-req-parameter page *rewind-parameter*))) + +(defmethod wcomponent-parameters ((cform cform)) + (list :id :required + :class nil + :action nil)) + +(defmethod wcomponent-template((cform cform)) + (let ((client-id (htcomponent-client-id cform)) + (class (wcomponent-parameter-value cform :class))) (when (null client-id) (setf client-id "")) + (when (null class) + (setf class "")) (form> :static-id client-id :name client-id - (wcomponent-informal-parameters o) + :class class + (wcomponent-informal-parameters cform) (input> :name *rewind-parameter* :type "hidden" :value client-id) - (htcomponent-body o)))) + (htcomponent-body cform))))
(defmethod wcomponent-before-rewind ((obj cform) (pobj page)) (setf (page-current-form pobj) obj))
(defmethod wcomponent-after-rewind ((obj cform) (pobj page)) - (let ((action (wcomponent-parameter-value obj :action))) - (unless (or (null action) (null (cform-rewinding-p obj pobj))) - (funcall (fdefinition action) pobj)) - (setf (page-current-form pobj) nil))) + (let ((validation-errors (aux-request-value :validation-errors)) + (action (wcomponent-parameter-value obj :action))) + (unless validation-errors + (when (or action (cform-rewinding-p obj pobj)) + (funcall (fdefinition action) pobj)) + (setf (page-current-form pobj) nil))))
;--------------------------------------------------------------------------------
@@ -94,34 +102,54 @@ (:default-initargs :result-as-list nil) (:documentation "Request cycle aware component the renders as an INPUT tag class"))
-(defmethod wcomponent-parameters ((o cinput)) - (list :id :required :reader nil :writer nil :visit-object nil :accessor nil :type :required)) +(defmethod wcomponent-parameters ((cinput cinput)) + (list :id :required + :reader nil + :writer nil + :visit-object nil + :accessor nil + :validator-handler nil + :class nil + :label nil + :validator nil + :type :required))
-(defmethod wcomponent-reserved-parameters ((o cinput)) +(defmethod wcomponent-reserved-parameters ((cinput cinput)) '(:value :name))
-(defmethod wcomponent-template ((obj cinput)) - (let ((client-id (htcomponent-client-id obj)) - (type (wcomponent-parameter-value obj :type)) - (visit-object (wcomponent-parameter-value obj :visit-object)) - (accessor (wcomponent-parameter-value obj :accessor)) - (reader (wcomponent-parameter-value obj :reader)) - (value "")) +(defmethod wcomponent-template ((cinput cinput)) + (let* ((client-id (htcomponent-client-id cinput)) + (type (wcomponent-parameter-value cinput :type)) + (visit-object (wcomponent-parameter-value cinput :visit-object)) + (accessor (wcomponent-parameter-value cinput :accessor)) + (reader (wcomponent-parameter-value cinput :reader)) + (class (wcomponent-parameter-value cinput :class)) + (value "") + (validation-errors (aux-request-value :validation-errors)) + (component-exceptions (assoc client-id validation-errors :test #'equal))) (when (null visit-object) - (setf visit-object (htcomponent-page obj))) + (setf visit-object (htcomponent-page cinput))) + (when (null class) + (setf class "")) + (when component-exceptions + (if (string= class "") + (setf class "error") + (setf class (format nil "~a error" class)))) (if (and (null reader) accessor) (setf value (funcall (fdefinition accessor) visit-object)) (setf value (funcall (fdefinition reader) visit-object))) (input> :static-id client-id :type type :name client-id + :class class :value value - (wcomponent-informal-parameters obj)))) + (wcomponent-informal-parameters cinput))))
(defmethod wcomponent-after-rewind ((obj cinput) (pobj page)) (let ((visit-object (wcomponent-parameter-value obj :visit-object)) (accessor (wcomponent-parameter-value obj :accessor)) - (writer (wcomponent-parameter-value obj :writer)) + (writer (wcomponent-parameter-value obj :writer)) + (validator (wcomponent-parameter-value obj :validator)) (new-value (page-req-parameter pobj (htcomponent-client-id obj) (cinput-result-as-list obj)))) @@ -130,7 +158,9 @@ (setf visit-object (htcomponent-page obj))) (if (and (null writer) accessor) (funcall (fdefinition `(setf ,accessor)) new-value visit-object) - (funcall (fdefinition writer) new-value visit-object))))) + (funcall (fdefinition writer) new-value visit-object)) + (when validator + (funcall validator)))))
;--------------------------------------------------------------------------------------- (defcomponent csubmit () () @@ -205,3 +235,55 @@ (wcomponent-informal-parameters obj) (htcomponent-body obj))))
+ +(defun component-id-and-value (component) + (let ((client-id (htcomponent-client-id component)) + (visit-object (wcomponent-parameter-value component :visit-object)) + (accessor (wcomponent-parameter-value component :accessor)) + (reader (wcomponent-parameter-value component :reader)) + (value "")) + (when (null visit-object) + (setf visit-object (htcomponent-page component))) + (if (and (null reader) accessor) + (setf value (funcall (fdefinition accessor) visit-object)) + (setf value (funcall (fdefinition reader) visit-object))) + (values client-id value))) + +(defun add-exception (id reason) + (let* ((validation-errors (aux-request-value :validation-errors)) + (component-exceptions (assoc id validation-errors :test #'equal))) + (if component-exceptions + (push reason (cdr component-exceptions)) + (push (cons id (list reason)) + (aux-request-value :validation-errors))))) + +(defun validator-required (component) + (multiple-value-bind (client-id value) + (component-id-and-value component) + (when (or (null value) (string= value "")) + (add-exception client-id + (format nil "Field ~a may not be null." (wcomponent-parameter-value component :label)))))) + +;; ------------------------------------------------------------------------------------ +(defcomponent exce (cinput) () + (:default-initargs :result-as-list t) + (:documentation "This component renders as a normal SELECT tag class, +but it is request cycle aware.")) + +(defmethod wcomponent-parameters :around ((obj cselect)) + (declare (ignore obj)) + (let ((params (call-next-method))) + (remf params :reader) + (remf params :type) + params)) + +(defmethod wcomponent-reserved-parameters ((obj cselect)) + (declare (ignore obj)) + '(:type :name)) + +(defmethod wcomponent-template ((obj cselect)) + (let ((client-id (htcomponent-client-id obj))) + (select> :static-id client-id + :name client-id + (wcomponent-informal-parameters obj) + (htcomponent-body obj)))) \ No newline at end of file
Modified: trunk/main/claw-core/src/misc.lisp ============================================================================== --- trunk/main/claw-core/src/misc.lisp (original) +++ trunk/main/claw-core/src/misc.lisp Tue Feb 19 06:24:12 2008 @@ -100,4 +100,4 @@
(defun login (&optional (request *request*)) "Perfoms a login action using the configuration object given for the request realm" - (configuration-login (current-config request))) \ No newline at end of file + (configuration-login (current-config request)))
Modified: trunk/main/claw-core/src/packages.lisp ============================================================================== --- trunk/main/claw-core/src/packages.lisp (original) +++ trunk/main/claw-core/src/packages.lisp Tue Feb 19 06:24:12 2008 @@ -71,6 +71,7 @@ :page-indent :page-xmloutput :page-doc-type + :page-current-component :htclass-body :htcomponent :htcomponent-page @@ -219,6 +220,7 @@ :csubmit> :submit-link :submit-link> + :validator-required :lisplet :lisplet-realm :lisplet-pages
Modified: trunk/main/claw-core/src/tags.lisp ============================================================================== --- trunk/main/claw-core/src/tags.lisp (original) +++ trunk/main/claw-core/src/tags.lisp Tue Feb 19 06:24:12 2008 @@ -109,6 +109,9 @@ See PAGE-BODY-INIT-SCRIPTS form more info. - PAGE is the page instance that must be given"))
+(defgeneric page-current-component (page) + (:documentation "The component being processed into one of the rendering phases")) + (defgeneric htcomponent-rewind (htcomponent page) (:documentation "This internal method is the first called during the request cycle phase. It is evaluated when a form action or an action-link action is fired. It is used to update all visit objects slots. @@ -353,6 +356,9 @@ (json-component-count :initarg :json-component-count :accessor page-json-component-count :documentation "Need to render the json object after an xhr call.") (request-parameters :initarg :request-parameters) + (components-stack :initform nil + :accessor page-components-stack + :documentation "A stack of components enetered into rendering process.") (url :initarg :url :accessor page-url :documentation "The URL provided with this page instance")) (:default-initargs :writer t @@ -631,6 +637,8 @@
tag-list))
+(defmethod page-current-component ((page page)) + (car (page-components-stack page))) ;;;========= HTCOMPONENT ============================ (defmethod htcomponent-can-print ((htcomponent htcomponent)) (let* ((id (htcomponent-client-id htcomponent)) @@ -659,13 +667,25 @@ (page-format-raw page """))))
(defmethod htcomponent-rewind :before ((htcomponent htcomponent) (page page)) - (setf (htcomponent-page htcomponent) page)) + (setf (htcomponent-page htcomponent) page) + (push htcomponent (page-components-stack page)))
(defmethod htcomponent-prerender :before ((htcomponent htcomponent) (page page)) - (setf (htcomponent-page htcomponent) page)) + (setf (htcomponent-page htcomponent) page) + (push htcomponent (page-components-stack page)))
(defmethod htcomponent-render :before ((htcomponent htcomponent) (page page)) - (setf (htcomponent-page htcomponent) page)) + (setf (htcomponent-page htcomponent) page) + (push htcomponent (page-components-stack page))) + +(defmethod htcomponent-rewind :after ((htcomponent htcomponent) (page page)) + (pop (page-components-stack page))) + +(defmethod htcomponent-prerender :after ((htcomponent htcomponent) (page page)) + (pop (page-components-stack page))) + +(defmethod htcomponent-render :after ((htcomponent htcomponent) (page page)) + (pop (page-components-stack page)))
(defmethod htcomponent-rewind ((htcomponent htcomponent) (page page)) (dolist (tag (htcomponent-body htcomponent)) @@ -702,7 +722,7 @@ (loop for (k v) on (htcomponent-attributes tag) by #'cddr do (progn (assert (keywordp k)) - (when v + (when (and v (string-not-equal v "")) (page-format page " ~a="~a"" (string-downcase (if (eq k :static-id) "id" @@ -890,16 +910,20 @@ :documentation "must be a plist or nil") (reserved-parameters :initarg :reserved-parameters :accessor wcomponent-reserved-parameters - :type cons :documentation "Parameters that may not be used in the constructor function") + :type cons + :documentation "Parameters that may not be used in the constructor function") (informal-parameters :initarg :informal-parameters :accessor wcomponent-informal-parameters - :type cons :documentation "Informal parameters are parameters optional for the component") + :type cons + :documentation "Informal parameters are parameters optional for the component") (allow-informal-parameters :initarg :allow-informal-parameters :reader wcomponent-allow-informal-parametersp - :allocation :class :documentation "Determines if the component accepts informal parameters") + :allocation :class + :documentation "Determines if the component accepts informal parameters") (template :initform nil :accessor wcomponent-template - :type htcomponent :documentation "The component template. What gives to each wcomponent its unique aspect and features")) + :type htcomponent + :documentation "The component template. What gives to each wcomponent its unique aspect and features")) (:default-initargs :informal-parameters nil :reserved-parameters nil :parameters nil
Modified: trunk/main/claw-core/tests/test1.lisp ============================================================================== --- trunk/main/claw-core/tests/test1.lisp (original) +++ trunk/main/claw-core/tests/test1.lisp Tue Feb 19 06:24:12 2008 @@ -99,7 +99,12 @@ (html> (head> (title> - (wcomponent-parameter-value o ':title))) + (wcomponent-parameter-value o ':title)) + (style> :type "text/css" +"input.error { + background-color: #FF9999; +} +")) (body> (wcomponent-informal-parameters o) (div> @@ -113,7 +118,6 @@ (defmethod page-content ((page auth-page)) (site-template> :title "Unauth test page" (p> "not here"))) -; (claw-require-authorization)) (lisplet-register-page-location *test-lisplet* 'auth-page "unauth.html") (lisplet-protect *test-lisplet* "unauth.html" '("admin" "user"))
@@ -233,7 +237,7 @@ (td> "Username") (td> (cinput> :id "username" - :type "text" + :type "text" :accessor 'login-page-username))) (tr> (td> "Password") @@ -256,38 +260,66 @@
(lisplet-register-page-location *test-lisplet* 'login-page "login.html" :login-page-p t)
-(defclass form-page (page) +(defclass user () + ((name :initarg :name + :accessor user-name) + (surname :initarg :surname + :accessor user-surname) + (gender :initarg :gender + :accessor user-gender)) + (:default-initargs :name "" :surname "" :gender "")) + +(defgeneric form-page-update-user (form-page)) + +(defclass form-page (page user) ((name :initarg :name :accessor form-page-name) (surname :initarg :surname :accessor form-page-surname) - (gender :initarg :gender - :reader form-page-gender - :writer setf-gender) (colors :initarg :colors - :accessor form-page-colors)) - + :accessor form-page-colors) + (gender :initarg :gender + :writer setf-gender + :accessor form-page-gender) + (user :initarg :user + :accessor form-page-user)) (:default-initargs :name "kiuma" :surname "surnk" :colors nil - :gender '("M"))) + :gender '("M") + :user (make-instance 'user))) + +(defmethod form-page-update-user ((form-page form-page)) + (let ((user (form-page-user form-page)) + (name (form-page-name form-page)) + (surname (form-page-surname form-page)) + (gender (first (form-page-gender form-page)))) + (setf (user-name user) name + (user-surname user) surname + (user-gender user) gender)))
(defmethod page-content ((o form-page)) (site-template> :title "a page title" - (cform> :id "testform" :method "post" + (cform> :id "testform" :method "post" :action 'form-page-update-user (table> (tr> (td> "Name") (td> (cinput> :id "name" :type "text" - :accessor 'form-page-name))) + :label "Name" + :validator #'(lambda () + (validator-required (page-current-component o))) + :accessor 'form-page-name)"*")) (tr> (td> "Surname") (td> (cinput> :id "surname" :type "text" - :accessor 'form-page-surname))) + :label "Name" + :validator #'(lambda () + (validator-required (page-current-component o))) + :accessor 'form-page-surname)"*")) (tr> (td> "Gender") (td> @@ -318,9 +350,12 @@ (tr> (td> :colspan "2" (csubmit> :id "submit" :value "OK"))))) - (div> (format nil "Name: ~a" (form-page-name o))) - (div> (format nil "Surname: ~a" (form-page-surname o))) - (div> (format nil "Gender: ~a" (first (form-page-gender o)))))) + (p> + (hr>) + (h2> "From result:") + (div> (format nil "Name: ~a" (user-name (form-page-user o)))) + (div> (format nil "Surname: ~a" (user-surname (form-page-user o)))) + (div> (format nil "Gender: ~a" (user-gender (form-page-user o)))))))
(lisplet-register-page-location *test-lisplet* 'form-page "form.html")