Skip to content

Instantly share code, notes, and snippets.

@html
Last active December 10, 2015 13:58
Show Gist options
  • Save html/4444927 to your computer and use it in GitHub Desktop.
Save html/4444927 to your computer and use it in GitHub Desktop.
Snippet allows to order fields in table view (columns in gridedit for example), use :fields-order view option like this :fields-order '(:id :name :group :time-created)
(defclass advanced-table-view (table-view)
((fields-order :initarg :fields-order :initform nil)))
(defclass advanced-table-view-field (table-view-field)
())
(defclass advanced-table-scaffold (table-scaffold)
())
(defun %map-object-view-fields (proc obj view-designator
&key include-invisible-p (expand-mixins t)
custom-fields &allow-other-keys)
"Implement `get-object-view-fields', except for consing up the
result list, instead calling PROC on each resulting `field-info'."
(labels ((map-level-fields (proc view)
(let ((view (or (and view (find-view view))
(return-from map-level-fields))))
(map-level-fields proc (view-inherit-from view))
(dolist (vfield (view-fields view))
(funcall proc vfield))))
(map-level (obj view mixin-container)
(let ((vfields (make-hash-table :test 'eq)))
;; prefer latest
(map-level-fields
(f_ (setf (gethash (view-field-slot-name _) vfields) _))
view)
(let ((fields))
(map-level-fields
(lambda (vfield)
;; we only use the in-order vfield as a tag into the
;; vfields HT, taking first-instance-only
(setf vfield (gethash (view-field-slot-name vfield) vfields))
(when vfield
(push vfield fields )
;; avoid duplicates
(remhash (view-field-slot-name vfield) vfields)))
view)
(when (and
(slot-exists-p (find-view view) 'fields-order)
(slot-boundp (find-view view) 'fields-order))
(let ((fields-order (slot-value (find-view view) 'fields-order)))
(setf fields
(sort fields
(lambda (&rest args)
(let ((keywords-weight
(loop for i in args collect
(let* ((keyword (intern
(string-upcase
(view-field-slot-name i))
"KEYWORD"))
(weight (if keyword
(if (find keyword fields-order)
(position keyword fields-order)
(1+ (length fields-order)))
0)))
weight))))
(apply #'> keywords-weight)))))))
(loop for vfield in (reverse fields) do
(let ((vfield-info (weblocks::make-field-info
:field vfield :object obj
:parent-info mixin-container)))
(etypecase vfield
(inline-view-field
(when (or include-invisible-p
(not (let ((hide-p-value (view-field-hide-p vfield)))
(if (functionp hide-p-value)
(funcall hide-p-value obj)
hide-p-value))))
(funcall proc vfield-info)))
(mixin-view-field
(if expand-mixins
(map-level
(and obj
(or (obtain-view-field-value vfield obj)
(aif (mixin-view-field-init-form vfield)
(funcall it)
(error "Slot for mixin field ~S has neither value nor initform!" vfield))))
(mixin-view-field-view vfield) vfield-info)
(funcall proc vfield-info))))))
))))
(multiple-value-bind (wproc terminate-proc)
(weblocks::inserting-custom-fields obj proc custom-fields)
(setf proc wproc)
(map-level obj view-designator nil)
(funcall terminate-proc))))
(defun map-view-fields (fn view obj &rest args)
"Acts like mapcar for view fields. FN should expect a structure of
type field-info."
(let ((expansion '()))
(apply #'%map-object-view-fields
(f_ (push (funcall fn _) expansion)) obj view args)
(nreverse expansion)))
(defmethod render-view-field-header :around ((field table-view-field)
(view advanced-table-view)
widget
(presentation hidden-presentation) value obj &rest args)
(declare (ignore args)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment