Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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)))
@svetlyak40wt

This comment has been minimized.

Copy link
Owner Author

@svetlyak40wt svetlyak40wt commented Sep 24, 2020

Here is a Gif with a demo:

2020-09-24 23 08 21

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment