Example of autocompletion box using Weblocks
;; This example illustrates how to call actions from JS and update the widget in response. | |
;; It is incomplete but could be refactored into reusable library. | |
;; Hope, somebody will do this some day. | |
(defpackage #:weblocks-autocomplete | |
(:use #:cl)) | |
(in-package weblocks-autocomplete) | |
(ql:quickload '(weblocks log4cl)) | |
(defparameter *data-to-complete* | |
(list | |
"Ahmedabad" | |
"Alexandria" | |
"Atlanta" | |
"Baghdad" | |
"Bangalore" | |
"Bangkok" | |
"Barcelona" | |
"Beijing" | |
"Belo Horizonte" | |
"Bogot√°" | |
"Buenos" | |
"Cairo" | |
"Chengdu" | |
"Chennai" | |
"Chicago" | |
"Chongqing" | |
"Dalian" | |
"Dallas" | |
"Dar es Salaam" | |
"Delhi" | |
"Dhaka" | |
"Dongguan" | |
"Foshan" | |
"Fukuoka" | |
"Guadalajara" | |
"Guangzhou" | |
"Hangzhou" | |
"Harbin" | |
"Ho Chi Minh City" | |
"Hong Kong" | |
"Houston" | |
"Hyderabad" | |
"Istanbul" | |
"Jakarta" | |
"Jinan" | |
"Johannesburg" | |
"Karachi" | |
"Khartoum" | |
"Kinshasa" | |
"Kolkata" | |
"Kuala Lumpur" | |
"Lagos" | |
"Lahore" | |
"Lima" | |
"London" | |
"Los" | |
"Luanda" | |
"Madrid" | |
"Manila" | |
"Mexico" | |
"Miami" | |
"Moscow" | |
"Mumbai" | |
"Nagoya" | |
"Nanjing" | |
"New" | |
"Osaka" | |
"Paris" | |
"Philadelphia" | |
"Pune" | |
"Qingdao" | |
"Rio" | |
"Riyadh" | |
"Saint Petersburg" | |
"Santiago" | |
"Seoul" | |
"Shanghai" | |
"Shenyang" | |
"Shenzhen" | |
"Singapore" | |
"Surat" | |
"Suzhou" | |
"S√£o" | |
"Tehran" | |
"Tianjin" | |
"Tokyo" | |
"Toronto" | |
"Washington, D.C." | |
"Wuhan" | |
"Xi'an" | |
"Yangon")) | |
(weblocks/widget:defwidget completions () | |
((visible :initform nil | |
:reader completions-visible) | |
(items :initform nil | |
:reader completions-list))) | |
(weblocks/widget:defwidget autocomplete-box () | |
((action-code :initarg :action-code | |
:reader action-code) | |
(completions :initform (make-instance 'completions) | |
:reader completions))) | |
(defmethod autocomplete ((widget autocomplete-box) &rest args) | |
(log:info "Autocompleting" args) | |
(let* ((completions (completions widget)) | |
(text (getf args :value))) | |
(setf (slot-value completions 'items) | |
(remove-if-not (lambda (item) | |
(str:starts-with-p text item :ignore-case t)) | |
*data-to-complete*)) | |
(setf (slot-value completions 'visible) | |
t) | |
(weblocks/widget:update completions))) | |
(defmethod initialize-instance :after ((obj autocomplete-box) &rest args) | |
(declare (ignorable args)) | |
(setf (slot-value obj 'action-code) | |
(weblocks/actions::function-or-action->action | |
(lambda (&rest args) | |
(apply #'autocomplete obj args))))) | |
(defmethod weblocks/widget:render ((box autocomplete-box)) | |
(let ((js-code | |
(format nil "initiateActionWithArgs(\"~A\", \"\", {\"value\": this.value})" | |
(action-code box)))) | |
(weblocks/html:with-html | |
(:input :type "text" | |
:placeholder "Autocomplete" | |
:oninput js-code) | |
(weblocks/widget:render (completions box))))) | |
(defmethod weblocks/widget:render ((widget completions)) | |
(let ((style (if (completions-visible widget) | |
(format nil "position:absolute;z-index:1000;background:#F1F1F1;list-style:none;padding:5px;") | |
(format nil "display:hidden")))) | |
(weblocks/html:with-html | |
(:ul :style style | |
(loop for item in (completions-list widget) | |
do (:li item)))))) | |
(weblocks/app:defapp test-app | |
:prefix "/") | |
(weblocks/widget:defwidget index-page () | |
((input :initform (make-instance 'autocomplete-box) | |
:reader input))) | |
(defmethod weblocks/widget:render ((widget index-page)) | |
(weblocks/html:with-html | |
(:p "This is a demo of the autocompletion widget:") | |
(weblocks/widget:render (input widget)) | |
(:p "A text to check that completion results will float above."))) | |
(defmethod weblocks/session:init ((app test-app)) | |
(declare (ignorable app)) | |
(make-instance 'index-page)) | |
;; This should be used to add JS and CSS to the widget | |
;; Examples can be found in the Ultralisp's code: | |
;; https://github.com/ultralisp/ultralisp/blob/f46cbaf6e8626e52ba0ca632bc50ae9261060f18/src/github/widgets/repositories.lisp#L448-L475 | |
;; (defmethod weblocks/dependencies:get-dependencies ((box autocomplete-box)) | |
;; (append (call-next-method) | |
;; (weblocks/dependencies:make-dependency))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Here is a Gif with a demo: