From achiumenti at common-lisp.net Tue Jan 13 13:03:03 2009 From: achiumenti at common-lisp.net (Andrea Chiumenti) Date: Tue, 13 Jan 2009 13:03:03 +0000 Subject: [claw-cvs] r184 - in trunk/main/claw-html: . src Message-ID: Author: achiumenti Date: Tue Jan 13 13:03:03 2009 New Revision: 184 Log: Added html template capabilities for pages and components Added: trunk/main/claw-html/src/parser.lisp Modified: trunk/main/claw-html/claw-html.asd trunk/main/claw-html/src/meta.lisp trunk/main/claw-html/src/packages.lisp trunk/main/claw-html/src/tags.lisp Modified: trunk/main/claw-html/claw-html.asd ============================================================================== --- trunk/main/claw-html/claw-html.asd (original) +++ trunk/main/claw-html/claw-html.asd Tue Jan 13 13:03:03 2009 @@ -31,10 +31,11 @@ :name "claw-html" :author "Andrea Chiumenti" :description "Common Lisp Active Web HTML generator." - :depends-on (:closer-mop :local-time :parenscript :cl-ppcre :split-sequence) + :depends-on (:closer-mop :local-time :parenscript :cl-ppcre :split-sequence :closure-html) :components ((:module src :components ((:file "packages") (:file "meta" :depends-on ("packages")) + (:file "parser" :depends-on ("packages")) (:file "tags" :depends-on ("packages" "meta")) (:file "components" :depends-on ("tags" "meta")) (:file "validators" :depends-on ("components")) Modified: trunk/main/claw-html/src/meta.lisp ============================================================================== --- trunk/main/claw-html/src/meta.lisp (original) +++ trunk/main/claw-html/src/meta.lisp Tue Jan 13 13:03:03 2009 @@ -29,6 +29,9 @@ (in-package :claw-html) +(defvar *components-templates* (make-hash-table) + "Hash table that stores the templates for CLAW components") + (defclass metacomponent (standard-class) () (:documentation "This is the meta class the must be set for every WCOMPONENT. Modified: trunk/main/claw-html/src/packages.lisp ============================================================================== --- trunk/main/claw-html/src/packages.lisp (original) +++ trunk/main/claw-html/src/packages.lisp Tue Jan 13 13:03:03 2009 @@ -31,7 +31,7 @@ (defpackage :claw-html - (:use :cl :closer-mop :local-time :parenscript :cl-ppcre :split-sequence) + (:use :cl :closer-mop :local-time :parenscript :cl-ppcre :split-sequence :closure-html) (:shadow :flatten) (:documentation "A comprehensive web application framework and server for the Common Lisp programming language") (:export #:*html-4.01-strict* @@ -43,6 +43,7 @@ #:*rewind-parameter* #:*validation-errors* #:*claw-current-page* + #:*claw-this-component* #:error-page #:render-error-page @@ -51,6 +52,7 @@ #:build-tagf #:page #:page-before-render + #:template #:page-render #:make-page-renderer #:page-current-form @@ -60,7 +62,7 @@ #:page-global-initscripts #:page-initscripts #:page-initstyles - #:page-current-component + #:current-component #:page-body-initscripts #:htcomponent #:htcomponent-page @@ -83,6 +85,8 @@ #:htstring #:$> #:$raw> + #:htignore + #:ignore> ;empty tags definition #:*empty-tags* #:area> @@ -177,6 +181,7 @@ #:u> #:ul> #:var> + #:parse-claw-template ;; class modifiers #:page-content #:generate-id Added: trunk/main/claw-html/src/parser.lisp ============================================================================== --- (empty file) +++ trunk/main/claw-html/src/parser.lisp Tue Jan 13 13:03:03 2009 @@ -0,0 +1,125 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: src/components.lisp $ + +;;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :claw-html) + +(defclass claw-html-builder (chtml::lhtml-builder) + ()) + +(defun make-claw-html-builder () + (make-instance 'claw-html-builder)) + +(defmethod hax:start-element ((handler claw-html-builder) name attrs) + (let* ((parent (car (chtml::stack handler))) + (this (list (find-symbol (format nil "~a>" (string-upcase name)) :claw-html) + (flatten (chtml::pt-attributes-to-lhtml attrs))))) + (push this (chtml::stack handler)) + (if parent + (push this (cddr parent)) + (setf (chtml::root handler) this)))) + +(defmethod hax:end-element ((handler claw-html-builder) name) + (let ((current (pop (chtml::stack handler)))) + (setf (cdr current) + (append (cadr current) (reverse (cddr current)))))) + +;; component parser + +(defvar *component-content-template* nil) + +(defclass claw-html-component-builder (claw-html-builder) + ((component-content-template :initform nil + :accessor component-content-template-p) + (component-content-ignore :initform nil + :accessor component-content-ignore-p) + (parsed-content :initform nil + :accessor parsed-content))) + +(defun make-claw-html-component-builder () + (make-instance 'claw-html-component-builder)) + +(defmethod hax:start-element :before ((handler claw-html-builder) name attrs) + (dolist (attr attrs) + (cond + ((and (string-equal (hax:attribute-name attr) "CLAWTYPE") + (string-equal (hax:attribute-value attr) "$ignore$")) + (setf (component-content-ignore-p handler) t)) + ((and (string-equal (hax:attribute-name attr) "CLAWTYPE") + (string-equal (hax:attribute-value attr) "$content$") + (null (component-content-ignore-p handler))) + (if (component-content-template-p handler) + (error "$content$ found multiple times in template") + (setf (component-content-template-p handler) t)))))) + +(defun parse-attributes (attrs) + (loop for (key value) on attrs by #'cddr + collect key + when value collect (parse-attribute-value value))) + +(defun parse-attribute-value (value) + (multiple-value-bind (result matchesp) + (cl-ppcre:regex-replace "(?i)(^\\$lisp>)+([.])*" value "\\2") + (if matchesp + (read-from-string result) + result))) + + +(defmethod hax:end-element ((handler claw-html-component-builder) name) + (let ((current (pop (chtml::stack handler)))) + (let ((attrs (parse-attributes (cadr current)))) + (cond + ((string-equal (getf attrs :clawtype) "$ignore$") + (setf (cdr current) nil + attrs nil + (component-content-ignore-p handler) nil + (car current) (find-symbol "IGNORE>" "CLAW-HTML"))) + ((string-equal (getf attrs :clawtype) "$body$") + (setf (cdr current) nil + attrs (list (find-symbol "*CLAW-THIS-COMPONENT*" "CLAW-HTML")) + (car current) (find-symbol "HTCOMPONENT-BODY" "CLAW-HTML"))) + ((and (component-content-template-p handler) + (string-equal (getf attrs :clawtype) "$content$") + (null (parsed-content handler))) + (remf attrs :clawtype) + (setf (parsed-content handler) (append (list (first current)) + attrs + (reverse (cddr current)))))) + (unless (component-content-ignore-p handler) + (setf (cdr current) + (append attrs (reverse (cddr current)))))))) + + +(defun parse-claw-template (input) + "Parses the input and returns a claw form template (i.e. a CLAW-HTML:TAG instance) and returns a lambda function with no parameters. +The inpus may be a string a file or a stream. +" + (eval `(lambda () ,(let ((handler (make-claw-html-component-builder))) + (chtml:parse input handler) + (let ((result (parsed-content handler))) + (or (parsed-content handler) result)))))) \ No newline at end of file Modified: trunk/main/claw-html/src/tags.lisp ============================================================================== --- trunk/main/claw-html/src/tags.lisp (original) +++ trunk/main/claw-html/src/tags.lisp Tue Jan 13 13:03:03 2009 @@ -301,6 +301,9 @@ "The CLAW page currently rendering ") +(defvar *calw-this-component* nil + "Variable set when rendering a WCOMPONENT-TEMPLATE so it is accessible inside the template") + (defvar *id-table-map* (make-hash-table :test 'equal) "Holds an hash table of used components/tags id as keys and the number of their occurrences as values. So if you have a :id \"compId\" given to a previous component, the second @@ -396,6 +399,7 @@ (id (getf attributes :id)) (static-id (getf attributes :static-id)) (render-condition (getf attributes :render-condition)) + (claw-type (getf attributes :clawtype)) (real-id (or static-id id)) (instance)) (when static-id @@ -403,19 +407,27 @@ (setf id nil)) (when render-condition (remf attributes :render-condition)) - (setf instance (make-instance parent - :empty emptyp - :real-id real-id - :name (string-downcase tag-name) - :render-condition render-condition - :attributes attributes - :body (second fbody))) - (when real-id - (if (null static-id) - (when (and id-table-map id) - (setf (htcomponent-client-id instance) (generate-id id))) - (setf (htcomponent-client-id instance) static-id))) - instance)) + (if claw-type + (let (clawtype-sybol-list (split "([:]){1,2}" (string-upcase claw-type))) + (if (second clawtype-sybol-list) + (setf claw-type (find-symbol (second clawtype-sybol-list) + (first clawtype-sybol-list))) + (setf claw-type (find-symbol (first clawtype-sybol-list)))) + (make-component claw-type attributes (second fbody))) + (progn + (setf instance (make-instance (or claw-type parent) + :empty emptyp + :real-id real-id + :name (string-downcase tag-name) + :render-condition render-condition + :attributes attributes + :body (second fbody))) + (when real-id + (if (null static-id) + (when (and id-table-map id) + (setf (htcomponent-client-id instance) (generate-id id))) + (setf (htcomponent-client-id instance) static-id))) + instance)))) (defun generate-tagf (tag-name emptyp) "Internal function that generates an htcomponent creation function from the component class name @@ -487,7 +499,10 @@ :documentation "Symbol for page charset encoding \(Such as UTF-8)") (injection-writing-p :initform nil :accessor page-injection-writing-p - :documentation "Flag that becomes true when rendering page injections")) + :documentation "Flag that becomes true when rendering page injections") + (teamplate :initarg :template + :accessor template + :documentation "A lambda function with no parameters that, when not nil, is used as page-content.")) (:default-initargs :writer t :external-format-encoding :utf-8 :script-files nil @@ -501,9 +516,14 @@ :xmloutput nil :doc-type *html-4.01-transitional* :request-parameters nil + :template nil :mime-type "text/html") (:documentation "A page object holds claw components to be rendered") ) +(defmethod page-content ((page page)) + (when-let (lambda-content (template page)) + (funcall lambda-content))) + (defun make-page-renderer (page-class http-post-parameters http-get-parameters) "Generates a lambda function from PAGE-RENDER method, that may be used into LISPLET-REGISTER-FUNCTION-LOCATION" #'(lambda () (with-output-to-string (*standard-output*) @@ -572,6 +592,10 @@ (:default-initargs :raw nil) (:documentation "Component needed to render strings")) +(defclass htignore (htcomponent) + () + (:documentation "Ignore all content")) + (defmethod initialize-instance :after ((inst tag) &rest keys) @@ -589,6 +613,11 @@ "Creates a non escaping htstring component" (make-instance 'htstring :body value :raw t)) +(defun ignore> (&rest ignore) + "Creates an ignore content" + (declare (ignore ignore)) + (make-instance 'htignore)) + (defclass htscript (tag) () (:documentation "Creates a component for rendering a