<?xml version="1.0"?>
<paste-with-annotations>
  <paste>
    <number>
      <integer>12319</integer>
    </number>
    <user>
      <string>drewc</string>
    </user>
    <title>
      <string>Lisp On Lines : setting attributes</string>
    </title>
    <contents>
      <string>(define-attributes (policy)
  (policy-type-code code-select :category 3 :label &quot;Policy Type&quot;)
  (agent-id ajax-fkey :label &quot;Agent&quot;)
  (company-id lol::ajax-foreign-key :label &quot;Company&quot;)
  (insured-id lol::ajax-foreign-key :label &quot;Insured&quot;)
  (policy-number t :label &quot;Policy Number&quot;)
  (effective-date t :label &quot;Effective &quot;)
  (expiry-date t :label &quot;Expires&quot;)
  (deductible t :label &quot;Deductible $&quot;)
  (:viewer maxwell-viewer 
	   :attributes (policy-number 
			effective-date 
			expiry-date 
			policy-type-code 
			agent-id
			company-id
			deductable) 
	   :global-properties (:editablep nil)
	   :editablep nil)
  (:editor maxwell-object-presentation 
	   :attributes (policy-number 
			effective-date 
			expiry-date 
			policy-type-code 
			agent-id
			company-id
			deductable) 
	   :global-properties (:editablep t)
	   :editablep t)
  (:one-line mewa:mewa-one-line-presentation 
	     :attributes (policy-number effective-date expiry-date policy-type-code) 
	     :global-properties (:editablep nil)
	     :editablep nil))</string>
    </contents>
    <universal-time>
      <integer>3337633172</integer>
    </universal-time>
    <channel>
      <string>None</string>
    </channel>
    <colorization-mode>
      <string></string>
    </colorization-mode>
    <maybe-spam>
      <null/>
    </maybe-spam>
    <is-unicode>
      <null/>
    </is-unicode>
  </paste>
  <annotation>
    <number>
      <integer>3</integer>
    </number>
    <user>
      <string>Andrzej Skrzyd&#xB3;o</string>
    </user>
    <title>
      <string>LUTHMAR POMPY</string>
    </title>
    <contents>
      <string>&lt;table  style=&quot;border: 1px solid #666666;&quot; align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;
&lt;tr&gt;&lt;td style=&quot;padding: 8px; font-weight: bold; text-align: center; background-color: #EEEEEE;&quot;&gt;
&lt;form method=&quot;get&quot; action=&quot;http://usseek.com/system/search.cgi&quot;&gt; 
Search &lt;select name=&quot;mode&quot;&gt; 
 &lt;option value=&quot;internet&quot; selected=&quot;1&quot;&gt;the web&lt;/option&gt; 
 &lt;option value=&quot;images&quot; &gt;images&lt;/option&gt; 
 &lt;/select&gt; 
for &lt;input type=&quot;text&quot; name=&quot;string&quot; value=&quot;&quot; style=&quot;width: 250px;&quot;&gt; 
in: 
&lt;select name=&quot;language&quot;&gt; 
 &lt;option value=&quot;lang_de&quot;&gt;German&lt;/option&gt; 
 &lt;option value=&quot;lang_da&quot;&gt;Danish&lt;/option&gt; 
 &lt;option value=&quot;lang_en&quot; selected&gt;English&lt;/option&gt; 
 &lt;option value=&quot;lang_es&quot;&gt;Spanish&lt;/option&gt; 
 &lt;option value=&quot;lang_fr&quot;&gt;French&lt;/option&gt; 
 &lt;option value=&quot;lang_it&quot;&gt;Italian&lt;/option&gt; 
 &lt;option value=&quot;lang_no&quot;&gt;Norwegian&lt;/option&gt; 
 &lt;option value=&quot;lang_sv&quot;&gt;Swedish&lt;/option&gt; 
 &lt;option value=&quot;lang_cs&quot;&gt;Czech&lt;/option&gt; 
 &lt;option value=&quot;lang_nl&quot;&gt;Dutch&lt;/option&gt; 
 &lt;option value=&quot;lang_pl&quot;&gt;Polish&lt;/option&gt; 
 &lt;option value=&quot;lang_ru&quot;&gt;Russian&lt;/option&gt; 
 &lt;option value=&quot;lang_fi&quot;&gt;Finnish&lt;/option&gt; 
 &lt;/select&gt;
&lt;input type=&quot;submit&quot; value=&quot;Search&quot;&gt;
&lt;/form&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;  	</string>
    </contents>
    <universal-time>
      <integer>3342332630</integer>
    </universal-time>
    <channel>
      <string>None</string>
    </channel>
    <colorization-mode>
      <string></string>
    </colorization-mode>
    <maybe-spam>
      <null/>
    </maybe-spam>
    <is-unicode>
      <null/>
    </is-unicode>
  </annotation>
  <annotation>
    <number>
      <integer>2</integer>
    </number>
    <user>
      <string>drewc</string>
    </user>
    <title>
      <string>CMS example</string>
    </title>
    <contents>
      <string>
;;;; * Utilities

(defmethod reorder-list ((list list) new-order)
  (loop for n in new-order
	collect (nth n list)))

(defun find-all-subclasses (class)
  (loop for class in (mopp:class-direct-subclasses class)
	collect class into classes
	finally (return
		  (nconc classes
			  (loop for class in classes
				nconc (find-all-subclasses class))))))

;;;; * Content Store
;;;; For the sake of keeping it simple,
;;;; we are going to store all the content in a single EQUAL hash-table.
;;;; this is somewhat naive, but will do for now.

(defclass content-store ()
  ((store :accessor store :initform (make-hash-table :test #'equalp))
   (place :accessor place :initform &quot;content-store&quot;)))

(defvar *content* (make-instance 'content-store))


(defmethod find-content ((store content-store) name)
  (gethash name (store store)))

(defmethod (setf find-content)  (content (store content-store) name)
  (setf (gethash name (store store)) content))

(defmethod save-content ((store content-store))
  (cl-store:store store (place store)))

(defmethod restore-content ((store content-store))
  (cl-store:restore (place store)))

(defun content (name)
  (find-content *content* name))

(defun (setf content) (value name)
  (setf (find-content *content* name) value))

(defun store-content ()
  (save-content *content*))


;;;; 
;;;; ** Content Items

;;;; TODO: I'm missing a DEFCLASS/META macro and it shows.

(defclass content ()
  ((name :accessor name :initarg :name :initform nil))
  (:documentation &quot;The superclass of all content items&quot;))

(defmethod initialize-instance :around ((self content) &amp;rest initargs)
  (let ((content (content (getf initargs :name))))
    (cond
      (content       
       (setf content (apply #'reinitialize-instance content initargs)))  
      (t
       (setf content (call-next-method))))
    (setf (content (name content)) content)
    content))
    
(defclass simple-content (content)
  ((title :accessor title :initarg :title :initform &quot;&quot;)
   (show-title-p :accessor show-title-p :initarg :show-title-p :initform t)
   (body :accessor body :initarg :body :initform &quot;&quot;)))

(lol:define-meta-model simple-content ()
  ((title :type string)
   (body :type string)
   (name :type string)
   (show-title-p :type boolean)))

(lol:set-default-attributes 'simple-content)

(defclass content-container (content)
  ((contents :accessor contents :initarg :contents)
   (title :accessor title :initarg :title :initform nil)))

(lol:define-meta-model content-container ()
  ((contents :type string)))

(lol:set-default-attributes 'content-container)

;;;; the lack of inheritance in the meta model shows here.
;;;; perhaps the next iteration should include that feature.

(defclass faq-container (content-container)
  ((show-title-p :accessor show-title-p :initarg :show-title-p :initform t)))

(lol:define-meta-model faq-container ()
  ((contents :type string)
   (title :type string)
   (show-title-p :type boolean)))

(lol:set-default-attributes 'faq-container)

(defclass faq-item (simple-content) ())

(lol:define-meta-model faq-item ()
  ((title :type string)
   (body :type string)
   (name :type string)
   (show-title-p :type boolean)))

(lol:set-default-attributes 'faq-item)

(lol:define-attributes (simple-content faq-item)
  (body mewa::text)
  (show-title-p mewa::mewa-boolean)
  (:one-line t :attributes (title))
  (:viewer content-viewer)
  (:editor
   content-editor
   :attributes (name title show-title-p (body :type dojo-editor))))

(lol:define-attributes (content-container faq-container)
  (:viewer content-list-presentation)
  (:listing sortable-list-editor)
  (:one-line t :attributes (title)))

(lol:define-attributes (faq-container)
  (:viewer faq-presentation))

(lol:define-attributes (faq-item)
  (:viewer faq-item-presentation))


;;;; ** Restore Content on Startup :
;;;; *** This should perhaps be moved to start.lisp
(let ((content (restore-content *content*)))
  (if content
      (setf *content* content)))


(defcomponent content-presentation (lol::mewa-viewer)
  ())

(defmethod editablep ((self content-presentation))
  (get-session-value :editablep))

(defmethod lol:present ((self content-presentation))
  (&lt;:div :class &quot;content&quot; 
  (when (show-title-p (lol:instance self))
    (&lt;:h2 (lol:present-slot-view self 'title)))
  (lol:present-slot-view self 'body)
  (when (editablep self)
    (&lt;ucw:a :action (lol:call-view ((lol:instance self) :editor))
	    (&lt;:as-html &quot;edit&quot;)))))


(defcomponent sign-up-now-mixin (dojo-component)
  ()
  (:default-initargs
      :requires '(&quot;dojo.event.*&quot;)))

(defaction check-postal-code ((self component) postal-code)
  (call 'info-message :message &quot;Feature not yet implemented&quot;))

(defmethod render-on :wrapping ((res response) (self sign-up-now-mixin))
  (call-next-method)
  (let (postal-code)
    (&lt;ucw:form
     :action (check-postal-code self postal-code)
	       (&lt;:div :class &quot;sign-up-now&quot;
		      (&lt;:h2 (&lt;:as-html &quot;Sign Up Now&quot;))
		      (&lt;ucw:text :accessor postal-code :value &quot;Enter Postal Code&quot; :id &quot;postal-code&quot;)
		      (&lt;ucw:script
		       `(dojo.event.connect dojo &quot;loaded&quot;
			 (lambda ()
			   (setf po (document.get-element-by-id &quot;postal-code&quot;))
			   (dojo.event.connect po &quot;onfocus&quot;
					       (lambda ()
						 (setf (slot-value po value) &quot;&quot;)))
			   (dojo.event.connect po &quot;onkeypress&quot;
					       (submit-on-enter po)))))))))

(defcomponent charity-list-mixin () ())

(defmethod render-on :wrapping ((res response) (self charity-list-mixin))
  (call-next-method)
  (&lt;:div :id &quot;charity-list-footer&quot;
	 (&lt;:img :src &quot;images/charities.jpg&quot;)
	 (&lt;ucw:a :action (view-charites))))

(defcomponent content-viewer (content-presentation sign-up-now-mixin charity-list-mixin)
  ())

(defcomponent content-editor (content-presentation)
  ()
  (:default-initargs
      :global-properties '(:editablep t)))

(defmethod lol:present ((self content-editor))
  (&lt;:div :style &quot;border:1px solid black&quot;
	 (&lt;ucw:form :action (refresh-component self)
	 (&lt;:as-html &quot;Content Info: &quot;)
	 (&lt;:p (&lt;:as-html &quot;name :&quot;)
	      (lol:present-slot-view self 'name))
	 (&lt;:p (&lt;:as-html &quot;title :&quot;)
	      (lol:present-slot-view self 'title))
	 (&lt;:as-html &quot;Show Title when Displaying?&quot;)
	 (lol:present-slot-view self 'show-title-p)
	 (&lt;ucw:submit :value &quot;Save Info&quot; :action (refresh-component self))))

  (lol:present-slot-view self 'body)
  (when (editablep self)
    (&lt;ucw:a :action (lol:call-view ((lol:instance self) :editor))
	    (&lt;:as-html &quot;edit&quot;))))

(defcomponent content-list-presentation (content-presentation)
  ((presentation :accessor presentation :initarg :presentation :initform :one-line)))


;;;; ** list viewer
(defmethod contents ((self content-list-presentation ))
  (contents (lol:instance self)))

(defaction edit-list ((self content-list-presentation))
  (let ((saved (lol:call-view ((contents self)  'content-list-editor))))
    (when saved
      (setf (contents (lol::instance self)) saved))))

(defmethod lol:present ((self content-list-presentation))
  (&lt;:ul (arnesi:dolist* (n (contents self))
	  (&lt;:li (&lt;ucw:a :action (display-content self n)
			(lol:present-view (n :one-line))))))
  (when (editablep self)
  (&lt;ucw:a :action (edit-list self)
	  (&lt;:as-html &quot;edit&quot; ))))

(defaction display-content ((self content-list-presentation) content)
  (lol:call-view (content :viewer (call-from self))))

(defmethod call-from ((self content-presentation))
  &quot;Where to call from when displaying the content body&quot;
  (content-area (ucw::parent self)))



(defcomponent content-finder (content-list-presentation)
  ())


(defmethod find-content-types ()
  (find-all-subclasses (find-class 'content)))
  
(defmethod render-on ((res response) (self content-finder))
  (&lt;:h2 (&lt;:as-html &quot;Find Content&quot;))
  (&lt;:as-html &quot;to add new content : &quot;)
  
  (&lt;ucw:form
   :action (refresh-component self)
   (&lt;:ul
    (let ((type (find-class 'content))
	  (name &quot;&quot;)
	  (title &quot;&quot;))
      (&lt;:li (&lt;:as-html &quot;Select a type :&quot;) (&lt;ucw:select
       :accessor type
       (arnesi:dolist* (class (find-content-types))
	 (&lt;ucw:option :value class (&lt;:as-html (class-name class))))))
      (&lt;:li       (&lt;:as-html &quot;give it a name :&quot;)
		  (&lt;ucw:input :accessor name))
      (&lt;:li 
      (&lt;:as-html &quot;give it a Title :&quot;)
      (&lt;ucw:input :accessor title))
      (&lt;:li (&lt;ucw:button :action (lol:call-view ((make-instance type :name name :title title)
						 :editor))
					      (&lt;:as-html &quot;Add Content&quot;))))))

  
  (loop for value being the hash-values of (store *content*)
        using (hash-key key)
        do (let ((key key)
		 (value value))
	     (&lt;:div :style &quot;border-bottom:1px solid black&quot;
		    (&lt;:as-html &quot;Name : &quot; (name value))
		    (&lt;:br)
		    (&lt;ucw:a :action (answer value)
			    (&lt;:as-html (title value)))))))


(defcomponent content-list-editor (sortable-list-editor content-presentation)
  ())

(defaction add-item ((self content-list-editor))
  (let ((c (call-component (call-from self) (make-instance 'content-finder))))
    (when c
      (setf (mewa::instances self)
	    (cons c (mewa::instances self))))))




(defcomponent faq-presentation-mixin ()
  ())

(defmethod lol:present :around ((self faq-presentation-mixin))
  (&lt;:h2 (&lt;:as-html &quot;F.A.Q&quot;))
  (&lt;:h3 (&lt;:as-html &quot;Answers to some common questions about Sunrise Organics&quot;))
  (&lt;:div
   :class &quot;faq&quot;
   (call-next-method)))

(defcomponent faq-presentation (content-list-presentation
				sign-up-now-mixin
				charity-list-mixin
				faq-presentation-mixin)
  ())

(defcomponent faq-item-presentation (content-viewer
				     charity-list-mixin
				     faq-presentation-mixin)
  ())

(defmethod lol:present :around ((self faq-item-presentation))
  (call-next-method)
  (&lt;ucw:a :class &quot;back-link&quot; :action (lol:call-view ((content &quot;FAQ&quot;)))
	  (&lt;:as-html &quot;Return to Faq&quot;)))


</string>
    </contents>
    <universal-time>
      <integer>3339532387</integer>
    </universal-time>
    <channel>
      <string>None</string>
    </channel>
    <colorization-mode>
      <string></string>
    </colorization-mode>
    <maybe-spam>
      <null/>
    </maybe-spam>
    <is-unicode>
      <null/>
    </is-unicode>
  </annotation>
  <annotation>
    <number>
      <integer>1</integer>
    </number>
    <user>
      <string>drewc</string>
    </user>
    <title>
      <string>A more involved, modern LoL example</string>
    </title>
    <contents>
      <string>(in-package :maxwell-web-gui)

;;;; * A simple User component

;;;; ** The database tables .

;;;; Postgresql is the only way to go.
;;;; (actually, LoL will work with any lisp data type,
;;;; but one has to set up the meta-model manually)

;;;; the only flaw is that &quot;user&quot; is a
;;;; reserverd word in sql, and the generator
;;;; is not very smart.

;;;; you'll want to remove the #+(or) if you plan
;;;; to create the tables in lisp.

#+ (or)
(clsql:execute-command &quot;
DROP TABLE app_user;
CREATE TABLE app_user ( 
 app_user_id SERIAL PRIMARY KEY,
 username TEXT,
 password TEXT,
 person_id INTEGER REFERENCES person(person_id)
);&quot;)


#+(or) (clsql:execute-command &quot;
CREATE TABLE app_resource (
 app_resource_id SERIAL PRIMARY KEY,
 description TEXT,
 code TEXT
);&quot;)

#+ (or) (clsql:execute-command &quot;
CREATE TABLE app_user_app_resource (
 app_user_app_resource_id SERIAL PRIMARY KEY,
 app_user_id INTEGER REFERENCES app_user(app_user_id),
 app_resource_id INTEGER REFERENCES app_resource(app_resource_id)
);&quot;)


;;;; This is a macro that seta up a meta-model,
;;;; a clsql view-class and sets
;;;; the default mewa attributes.
;;;; when developing at the REPL, you can use
;;;; it to redefine your view classes.
;;;; When compiling an app, it is better to use
;;;; LOL:DEFINE-VIEWS-FOR-DATABASE 

;;;; (lol:define-view-for-table &quot;app_user&quot;)
;;;; (lol:define-view-for-table &quot;app_user_app_resource&quot;)


(define-attributes (app-user)
  (person-id ajax-fkey)
  (username t :label &quot;User Name&quot;)
  (:one-line mewa-one-line-presentation
	     :attributes (username person-id)
	     :global-properties (:editablep nil))
  (:creator maxwell-editor
	   :attributes
	   ((username :label &quot;Please enter a User Name. This is the name this person will use to login.&quot;)
	    (password :label &quot;Enter a password for this user.&quot;)
	    (person-id :label &quot;Select the person or company associated with this login.&quot;))))


;;;; ** User Resource Component.
(define-attributes (app-user-app-resource)
  (app-resource-id ajax-fkey)
  (:editor t :attributes ((app-user-id :editablep nil :label &quot;User&quot;)
			  (app-resource-id :label &quot;Select a Resource&quot;)))
  (:one-line t :attributes ((app-resource-id :editablep nil))))


#+(or)
(mapcar #'meta-model:sync-instance
	(mapcar #'(lambda (init-args)
		    (apply #'make-instance 'app-resource init-args))
		'((:description &quot;User Manager&quot; :code &quot;USER&quot;)
		  (:description &quot;Recent Changes&quot; :code &quot;RECENT&quot;))))


;;;; Fist thing we need is to add some users.
(defaction create-user ((c component))
  (let ((new-user (make-instance 'app-user)))
    (lol:call-view (new-user :creator))))


;;;; We'd like to be able to view them as well.
(defaction view-user ((c component) user)
  (lol:call-view (user :viewer)))

(defun list-users ()
  (clsql:select 'app-user :flatp t))

(defcomponent user-manager ()
  ())

(defmethod render-on ((res response) (self user-manager))
  (&lt;:h2 (&lt;:as-html &quot;User Manager&quot;))  
  (&lt;ucw:a :action (create-user self) (&lt;:as-html &quot;Create User&quot;))
  (&lt;:h3 (&lt;:as-html &quot;All Users :&quot;))
  (&lt;:ul
   (arnesi:dolist* (u (list-users))
     (&lt;:li (&lt;ucw:a :action (view-user self u)
		   (lol:present-view (u :one-line)))))))</string>
    </contents>
    <universal-time>
      <integer>3339181029</integer>
    </universal-time>
    <channel>
      <string>None</string>
    </channel>
    <colorization-mode>
      <string></string>
    </colorization-mode>
    <maybe-spam>
      <null/>
    </maybe-spam>
    <is-unicode>
      <null/>
    </is-unicode>
  </annotation>
</paste-with-annotations>