Browse files

Support for non-AJAX drilldowns in datagrids. With these, the browser's

"back" button returns from the drilldown widget to the datagrid, as the
user might expect.

Example: you can have a datagrid of frobs selected by a 'navigation' at
''; the :drilldown-link-url-fn can return URLs like
''.  To do this, wrap the datagrid in a custom
subclass of 'on-demand-selector', with a :lookup-function that, if given
an empty list of tokens, returns the datagrid itself, otherwise returns
the drilldown widget named by the first token.
  • Loading branch information...
slburson committed Jul 2, 2012
1 parent e30ff0e commit ea7f43de354970cdaafe15e02fc288285de27313
Showing with 45 additions and 10 deletions.
  1. +22 −9 src/widgets/datagrid/drilldown.lisp
  2. +19 −0 src/widgets/dataseq/dataseq.lisp
  3. +4 −1 src/widgets/on-demand-selector.lisp
@@ -47,13 +47,14 @@
(defmethod with-table-view-body-row ((view table-view) obj (widget datagrid) &rest args
&key alternp &allow-other-keys)
(if (and (dataseq-allow-drilldown-p widget)
- (dataseq-on-drilldown widget))
- (let ((row-action (make-action
- (lambda (&rest args)
- (declare (ignore args))
- (when (dataseq-autoset-drilled-down-item-p widget)
- (setf (dataseq-drilled-down-item widget) obj))
- (funcall (cdr (dataseq-on-drilldown widget)) widget obj))))
+ (or (dataseq-on-drilldown widget) (dataseq-drilldown-link-url-fn widget)))
+ (let ((row-action (and (null (dataseq-drilldown-link-url-fn widget))
+ (make-action
+ (lambda (&rest args)
+ (declare (ignore args))
+ (when (dataseq-autoset-drilled-down-item-p widget)
+ (setf (dataseq-drilled-down-item widget) obj))
+ (funcall (cdr (dataseq-on-drilldown widget)) widget obj)))))
(drilled-down-p (and (dataseq-drilled-down-item widget)
(eql (object-id (dataseq-drilled-down-item widget))
(object-id obj)))))
@@ -64,11 +65,23 @@
(when alternp "altern")
(when (and alternp drilled-down-p) " ")
(when drilled-down-p "drilled-down")))
- :onclick (format nil "initiateActionOnEmptySelection(\"~A\", \"~A\");"
- row-action (session-name-string-pair))
+ :onclick (if (dataseq-drilldown-link-url-fn widget)
+ (format nil "window.location.assign(\"~A\");"
+ (funcall (dataseq-drilldown-link-url-fn widget) widget obj))
+ (format nil "initiateActionOnEmptySelection(\"~A\", \"~A\");"
+ row-action (session-name-string-pair)))
:onmouseover " = \"pointer\";"
:style "cursor: expression(\"hand\");"
(apply #'render-table-view-body-row view obj widget :row-action row-action args)))
(safe-apply (sequence-view-row-suffix-fn view) view obj args))
+(defmethod render-view-field-value (value (presentation text-presentation) (field table-view-field)
+ view (widget datagrid) obj
+ &rest args)
+ (declare (ignore args))
+ (if (eq (view-field-slot-name field) (dataseq-drilldown-link-field widget))
+ (with-html
+ (:a :href (funcall (dataseq-drilldown-link-url-fn widget) widget obj)
+ (call-next-method)))
+ (call-next-method)))
@@ -110,6 +110,25 @@
:documentation "If set to true and
'on-drilldown' isn't nil, dataseq provides the
UI to drill down into items.")
+ ;; Use this if you want the browser's "back" button to return to the
+ ;; dataseq after a drilldown. You'll probably want to subclass
+ ;; 'on-demand-selector' to handle the generated URLs.
+ (drilldown-link-url-fn :accessor dataseq-drilldown-link-url-fn
+ :initform nil
+ :initarg :drilldown-link-url-fn
+ :documentation
+ "If nonnull, drilldown is done by non-AJAX links.
+ This should be a function of two arguments, the
+ dataseq and the object, that returns the URL for
+ drilling down on the object.")
+ ;; Use this if you want the user to be able to tell which items they've
+ ;; already drilled down on, using the visited-link color.
+ (drilldown-link-field :accessor dataseq-drilldown-link-field
+ :initform nil
+ :initarg :drilldown-link-field
+ :documentation
+ "If 'drilldown-link-url-field' is nonnull, any
+ field with this name is rendered as an HTML link.")
(on-drilldown :accessor dataseq-on-drilldown
:initform nil
:initarg :on-drilldown
@@ -36,7 +36,10 @@ t (the default), calls the lookup-function to make a new one. Returns three
values -- a widget, a list of consumed tokens, and a list of remaining
(if (and (on-demand-selector-cache obj)
- (uri-tokens-start-with (remaining-tokens tokens) (car (on-demand-selector-cache obj))))
+ (let ((cache-tokens (car (on-demand-selector-cache obj))))
+ (if cache-tokens
+ (uri-tokens-start-with (remaining-tokens tokens) cache-tokens)
+ (null (remaining-tokens tokens)))))
;; we have the widget cached, consume the right amount of tokens
(pop-tokens tokens (length (car (on-demand-selector-cache obj))))

0 comments on commit ea7f43d

Please sign in to comment.