;;; -*- mode: Lisp; Syntax: Common-Lisp; -*-
;;;
;;; Copyright (c) 2009 by the authors.
;;;
;;; See LICENCE for details.
(in-package :hu.dwim.presentation)
;;;;;;
;;; target-place/widget
(def (component e) target-place/widget (standard/widget content/component)
((target-place :type place))
(:documentation "A TARGET-PLACE/WIDGET has a PLACE that refers into its CONTENT. This place can be set by REPLACE-TARGET-PLACE/WIDGET descendant COMPONENTs."))
(def (macro e) target-place/widget ((&rest args &key target-place &allow-other-keys) &body content)
;; evaluation of target-place must be after content
(remove-from-plistf args :target-place)
`(make-instance 'target-place/widget ,@args
:content ,(the-only-element content)
:target-place ,target-place))
(def constructor target-place/widget
(unless (slot-boundp -self- 'target-place)
(setf (target-place-of -self-) (make-object-slot-place -self- (find-slot (class-of -self-) 'content)))))
(def render-xhtml target-place/widget
)
;;;;;;
;;; replace-target-place/widget
;; TODO rename to replace-target-place/command/widget?
(def (component e) replace-target-place/widget (command/widget)
((replacement-component :type t))
(:documentation "A REPLACE-TARGET-PLACE/WIDGET is a COMMAND/WIDGET that will replace the TARGET-PLAGE of its nearest TARGET-PLACE/WIDGET ancestor."))
(def (macro e) replace-target-place/widget ((&rest args &key &allow-other-keys) content &body forms)
`(make-instance 'replace-target-place/widget ,@args
:content ,content
:replacement-component (one-time-delay ,@forms)))
(def constructor replace-target-place/widget
(setf (action-of -self-) (make-component-action -self-
(replace-target-place -self- (component-dispatch-class -self-) (component-dispatch-prototype -self-) (component-value-of -self-))))
(setf (subject-component-of -self-) (delay (find-subject-component-for-replace-target-place/widget -self-))))
(def function find-subject-component-for-replace-target-place/widget (widget)
(when-bind target-place/widget (find-replace-target-place-widget widget :otherwise nil)
(bind ((target-place (target-place-of target-place/widget))
(component (component-at-place target-place)))
(when (typep component 'parent/mixin)
;; TODO shouldn't it be in closer relationship with collect-covering-to-be-rendered-descendant-components ?
(find-ancestor-component-of-type 'id/mixin component :otherwise nil)))))
(def function render-replace-target-place-command/xhtml (component replacement-component content &rest args &key &allow-other-keys)
(apply 'render-command/xhtml (make-component-action component
(bind ((target-place (target-place-of (find-replace-target-place-widget component))))
(setf (component-at-place target-place) replacement-component)))
content args))
(def function find-replace-target-place-widget (component &key (otherwise :error otherwise?))
(or (find-ancestor-component-if (lambda (ancestor)
(and (typep ancestor 'target-place/widget)
(target-place-of ancestor)))
component :otherwise #f)
(handle-otherwise
(error "Unable to find the target-place/widget for ~A" component))))
(def (generic e) replace-target-place (component class prototype value)
(:method ((component replace-target-place/widget) class prototype value)
(bind ((target-place (target-place-of (find-replace-target-place-widget component)))
(replacement-component (force (replacement-component-of component))))
(setf (component-at-place target-place) replacement-component))))