| (in-package :forms) |
|
|
| (defclass list-form-field (form-field) |
| ((type :initarg :type |
| :initform (error "Provide the list type via :type") |
| :accessor list-field-type |
| :type function |
| :documentation "The list elements type.") |
| (empty-item-predicate :initarg :empty-item-predicate |
| :initform nil |
| :accessor empty-item-predicate |
| :type (or null function) |
| :documentation "A predicate that tells when a list item is considered empty, and so it is removed from the list") |
| (add-button :initarg :add-button |
| :initform t |
| :accessor add-button-p |
| :type boolean |
| :documentation "Whether have a list 'ADD' button or not") |
| (remove-button :initarg :remove-button |
| :initform t |
| :accessor remove-button-p |
| :type boolean |
| :documentation "Whether add an item removal button or not")) |
| (:documentation "A field that contains a list of elements (either other fields or subforms)")) |
|
|
| (defmethod make-form-field ((field-type (eql :list)) &rest args) |
| (let ((list-field-type (etypecase (getf args :type) |
| (list |
| (lambda () |
| (apply #'make-form-field |
| (first (getf args :type)) |
| (append (list :name '||) |
| (rest (getf args :type)))))) |
| (keyword (lambda () |
| (make-form-field |
| (getf args :type) |
| :name '||))) |
| (function (getf args :type))))) |
| (apply #'make-instance 'list-form-field :type list-field-type args))) |
|
|
| (defmethod field-read-from-request ((field list-form-field) form parameters) |
| |
| (let ((regex |
| (ppcre:create-scanner `(:sequence :start-anchor |
| ,(field-request-name field form) |
| "[" |
| (:register (:greedy-repetition 1 nil :digit-class)) |
| "]")))) |
| |
| (let ((request-list-indexes |
| (remove-duplicates |
| (loop for param in parameters |
| when (ppcre:scan regex (car param)) |
| collect (ppcre:register-groups-bind (index) |
| (regex (car param)) |
| (when (stringp index) |
| (parse-integer index))))))) |
| |
| (let ((items |
| (mapcar (lambda (i) |
| (let* ((*field-path* (cons (format nil "~a[~a]" |
| (string-downcase (string (field-name field))) |
| i) |
| (rest *field-path*))) |
| (item-field (funcall (list-field-type field)))) |
| (field-read-from-request item-field |
| form |
| parameters) |
| (field-value item-field))) |
| request-list-indexes))) |
| |
| (let ((items (if (empty-item-predicate field) |
| (remove-if (empty-item-predicate field) |
| items) |
| items))) |
| |
| (setf (field-value field) items)))))) |
|
|