Client side storage

This commit is contained in:
David Botton 2021-01-21 21:04:07 -05:00
parent f5cf78500a
commit c1c08db9b3
7 changed files with 129 additions and 10 deletions

View file

@ -138,6 +138,7 @@ Tutorial Summary
- 11-tutorial.lisp - Attaching to existing HTML
- 12-tutorial.lisp - Running a website in CLOG (routing)
- 13-tutorial/ - Flying Solo - A minimalist CLOG project
- 14-tutorial.lisp - Local (persistent) and Session client side storage
Demo Summary

View file

@ -174,10 +174,10 @@
;; reload ;;
;;;;;;;;;;;;
(defgeneric reload (clog-window)
(defgeneric reload (clog-location)
(:documentation "Reload browser window."))
(defmethod reload ((obj clog-window))
(defmethod reload ((obj clog-location))
(execute obj "reload()"))
;;;;;;;;;;;;;;;;;

View file

@ -468,8 +468,6 @@ If ON-ORIENTATION-CHANGE-HANDLER is nil unbind the event."))
;; set-on-storage ;;
;;;;;;;;;;;;;;;;;;;;
;; need to change to use a true on-storage event
(defparameter storage-event-script
"+ encodeURIComponent(e.originalEvent.key) + ':' +
encodeURIComponent(e.originalEvent.oldValue) + ':' +
@ -478,13 +476,13 @@ If ON-ORIENTATION-CHANGE-HANDLER is nil unbind the event."))
(defun parse-storage-event (data)
(let ((f (ppcre:split ":" data)))
(list
:key-value (quri:url-decode (nth 0 f))
:key (quri:url-decode (nth 0 f))
:old-value (quri:url-decode (nth 1 f))
:new-value (quri:url-decode (nth 2 f)))))
:value (quri:url-decode (nth 2 f)))))
(defgeneric set-on-storage (clog-window on-storage-handler)
(:documentation "Set the ON-STORAGE-HANDLER for CLOG-OBJ. If
ON-STORAGE-HANDLER is nil unbind the event."))
(:documentation "Set the ON-STORAGE-HANDLER for CLOG-OBJ. The
on-storage event is fired for changes to :local storage keys."))
(defmethod set-on-storage ((obj clog-window) handler)
(set-event obj "storage"
@ -492,3 +490,60 @@ ON-STORAGE-HANDLER is nil unbind the event."))
(lambda (data)
(funcall handler obj (parse-storage-event data))))
:call-back-script storage-event-script))
;;;;;;;;;;;;;;;;;;;;
;; storage-length ;;
;;;;;;;;;;;;;;;;;;;;
(deftype storage-type '(member local session))
(defgeneric storage-length (clog-window storage-type)
(:documentation "Number of entries in browser STORAGE-TYPE.
(local = persistant or session)"))
(defmethod storage-length ((obj clog-window) storage-type)
(parse-integer (query obj "~(~a~)Storage.length" storage-type)))
;;;;;;;;;;;;;;;;;
;; storage-key ;;
;;;;;;;;;;;;;;;;;
(defgeneric storage-key (clog-window storage-type key-num)
(:documentation "Return the key for entry number KEY-NUM in browser
STORAGE-TYPE. (local = persistant or session)"))
(defmethod storage-key ((obj clog-window) storage-type key-num)
(query obj (format nil "~(~a~)Storage.key(~A)" storage-type key-num)))
;;;;;;;;;;;;;;;;;;;;
;; storage-remove ;;
;;;;;;;;;;;;;;;;;;;;
(defgeneric storage-remove (clog-window storage-type key-name)
(:documentation "Remove the storage key and value in browser
STORAGE-TYPE. (local = persistant or session)"))
(defmethod storage-remove ((obj clog-window) storage-type key-name)
(execute obj (format nil "~(~a~)Storage.removeItem(~A)" storage-type key-name)))
;;;;;;;;;;;;;;;;;;;;;
;; storage-element ;;
;;;;;;;;;;;;;;;;;;;;;
(defgeneric storage-element (clog-window storage-type key-name)
(:documentation "Get/Setf storage-element on browser client."))
(defmethod storage-element ((obj clog-window) storage-type key-name)
(query obj (format nil "~(~a~)Storage.getItem('~A')"
storage-type
(escape-string key-name))))
(defgeneric set-storage-element (clog-window storage-type key-name value)
(:documentation "Set storage-element."))
(defmethod set-storage-element ((obj clog-window) storage-type key-name value)
(execute obj (format nil "~(~a~)Storage.setItem('~A','~A')"
storage-type
(escape-string key-name)
(escape-string value))))
(defsetf storage-element set-storage-element)

View file

@ -5,7 +5,7 @@
:author "David Botton <david@botton.com>"
:license "BSD"
:version "0.1.1"
:version "0.2.0"
:serial t
:depends-on (#:clack #:websocket-driver #:alexandria #:hunchentoot #:cl-ppcre
#:bordeaux-threads #:trivial-open-browser

View file

@ -471,6 +471,10 @@ embedded in a native template application.)"
(scroll-to generic-function)
(close-window generic-function)
(close-connection generic-function)
(storage-length generic-function)
(storage-key generic-function)
(storage-remove generic-function)
(storage-element generic-function)
"CLOG-Window - Events"
(set-on-abort generic-function)
@ -537,6 +541,7 @@ embedded in a native template application.)"
(export 'make-markup)
(defun make-markup ()
(load "clog.lisp")
(load "clog-docs.lisp")
(load "clog-base.lisp")
(load "clog-element.lisp")
(load "clog-element-common.lisp")
@ -554,6 +559,7 @@ embedded in a native template application.)"
(export 'make-html)
(defun make-html ()
(load "clog.lisp")
(load "clog-docs.lisp")
(load "clog-base.lisp")
(load "clog-element.lisp")
(load "clog-element-common.lisp")

56
tutorial/14-tutorial.lisp Normal file
View file

@ -0,0 +1,56 @@
(defpackage #:clog-user
(:use #:cl #:clog)
(:export start-tutorial))
(in-package :clog-user)
(defun on-new-window (body)
(set-on-click (create-button body :content "Set Local Key")
(lambda (obj)
(setf (storage-element (window body) :local "my-local-key")
(get-universal-time))
(reload (location body))))
(set-on-click (create-button body :content "Set Session Key")
(lambda (obj)
(setf (storage-element (window body) :session "my-session-key")
(get-universal-time))
(reload (location body))))
(set-on-storage (window body)
(lambda (obj data)
(create-div body :content
(format nil "<br>~A : ~A => ~A<br>"
(getf data ':key)
(getf data ':old-value)
(getf data ':value)))))
(create-div body :content (format nil
"<H1>Local Storage vs Session Storage</H1>
<p width=500>
The value of local storage persists in browser cache even after browser closed.
If you reset this page the session storage key will remain the same, but openning
in another window or tab will be a new session but if came from a click from this
window the session keys are copied first to the new window.</p>
<br>
<a href='.' target='_blank'>Another Window = Different Session</a><br>
<br>
<br>
Local Storage key: ~A := ~A<br>
<br>
Session Storage key: ~A := ~A<br>
<br>
Changes made to a local key will fire an event and print below:<br>"
"my-local-key"
(storage-element (window body) :local "my-local-key")
"my-session-key"
(storage-element (window body) :session "my-session-key")))
(run body))
(defun start-tutorial ()
"Start turtorial."
(initialize #'on-new-window)
(open-browser))

View file

@ -46,3 +46,4 @@ Tutorial Summary
- 11-tutorial.lisp - Attaching to existing HTML
- 12-tutorial.lisp - Running a website in CLOG (routing)
- 13-tutorial/ - Flying Solo - A minimalist CLOG project
- 14-tutorial.lisp - Local (persistent) and Session client side storage