From 0f35b8eee7bf30c399be64289cf5a54c95bd88ba Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Wed, 18 Mar 2026 08:57:46 +0100 Subject: [PATCH] - --- scrbl/wv-context.scrbl | 80 +++++++++++++ scrbl/wv-window.scrbl | 256 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 336 insertions(+) create mode 100644 scrbl/wv-context.scrbl create mode 100644 scrbl/wv-window.scrbl diff --git a/scrbl/wv-context.scrbl b/scrbl/wv-context.scrbl new file mode 100644 index 0000000..205876c --- /dev/null +++ b/scrbl/wv-context.scrbl @@ -0,0 +1,80 @@ +#lang scribble/manual + +@(require scribble/racket + scribble/example + scribble/core + (for-label racket/base + racket/class + racket/path + "../private/wv-settings.rkt" + "../private/racket-webview.rkt") + ) + +@defmodule[racket-webview] + +@title{Object-Oriented Interface: @racket[wv-context%]} +@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] + +@defclass[wv-context% object% ()]{ + +An OO wrapper around a webview context together with its associated settings. +A @racket[wv-context%] object creates and owns a webview context by calling +@racket[webview-new-context]. It also creates a corresponding @racket[wv-settings%] +instance for access to global and per-section settings. This class manages +construction of a webview context using a file getter and boilerplate JavaScript, +exposure of the created low-level context object via @racket[context], +access to the base URL of the created context via @racket[base-url] and +access to settings views via @racket[settings]. + +@defconstructor[([base-path path-string?] + [file-getter procedure? (webview-standard-file-getter base-path)] + [context-js procedure? (λ () "")] + [boilerplate-js procedure? (webview-default-boilerplate-js context-js)] + [ini object?])]{ +Creates a new @racket[wv-context%] object. + +The @racket[base-path] argument is used to construct the default +@racket[file-getter]. + +The @racket[file-getter] argument is passed to @racket[webview-new-context] +and is responsible for resolving files served by the context. + +The @racket[context-js] argument must be a procedure producing the JavaScript +snippet that should be injected into the context. + +The @racket[boilerplate-js] argument must be a procedure producing the final +boilerplate JavaScript used when constructing the context. By default it is +built from @racket[context-js] using @racket[webview-default-boilerplate-js]. + +The @racket[ini] argument is mandatory and supplies the settings backend used +for construction of the internal @racket[wv-settings%] object. If omitted, the +constructor raises an error. + +During initialization the class: + +@itemlist[#:style 'compact + @item{creates a new low-level context with @racket[webview-new-context];} + @item{creates a @racket[wv-settings%] object using @racket[ini] and the + global context identifier @racket['global].} +] +} + +@defmethod*[([(context) wv-context?])]{ +Returns the underlying webview context (struct) created during +initialization. +} + +@defmethod*[([(settings [section symbol?]) (is-a?/c wv-settings%)])] { +Returns a @tt{wv-settings%} object for @racket[section]. +This method delegates to the internally stored @racket[wv-settings%] object by +calling @racket[(send settings-obj clone section)]. The resulting object shares +the same @racket[ini] backend as the global settings object, but addresses the +supplied section. +} + +@defmethod*[([(base-url) any/c])] { +Returns the base URL of the underlying webview context. +This method delegates to @racket[wv-context-base-url]. +} + +} diff --git a/scrbl/wv-window.scrbl b/scrbl/wv-window.scrbl new file mode 100644 index 0000000..76daadc --- /dev/null +++ b/scrbl/wv-window.scrbl @@ -0,0 +1,256 @@ +#lang scribble/manual + +@(require scribble/racket + scribble/example + scribble/core + (for-label racket/base + racket/class + racket/path + net/url + "../private/wv-context.rkt" + "../private/wv-settings.rkt")) + +@defmodule[wv-window] + +@title{Object-Oriented Interface: @racket[wv-window%]} +@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] + +@defclass[wv-window% object% ()]{ + +An OO wrapper around a single webview window. +A @racket[wv-window%] object owns one low-level window created with +@racket[webview-create], keeps a per-window settings view, and offers methods for +window management, DOM element access, event binding, file dialogs, and message boxes. + +The class is designed so that subclasses can override event methods such as +@racket[moved], @racket[resized], @racket[page-loaded], @racket[js-event], +@racket[navigation-request], @racket[can-close?], and @racket[closed]. + +@defconstructor[([parent (or/c #f (is-a?/c wv-window%)) #f] + [wv-context (is-a?/c wv-context%) (if (eq? parent #f) + (error "wv context is mandatory") + (get-field wv-context parent))] + [html-path path-string? (error "html path is mandatory")] + [settings (is-a?/c wv-settings%) + (send wv-context settings + (string->symbol (format "~a" html-path)))] + [title string? "Racket Webview Window"] + [width (or/c #f exact-integer?) #f] + [height (or/c #f exact-integer?) #f] + [x (or/c #f exact-integer?) #f] + [y (or/c #f exact-integer?) #f] + [wv any/c #f])]{ +Creates a new window. + +The @racket[wv-context] argument supplies the underlying webview context. +If @racket[parent] is given, the default value of @racket[wv-context] is taken from it. +The @racket[html-path] argument identifies the HTML resource to open. +The default @racket[settings] object is derived from @racket[wv-context] using +@racket[html-path] as per-window settings key. + +The constructor creates the low-level window using @racket[webview-create] and then +calls @racket[init-size] to restore position and size from settings, falling back to +constructor arguments or internal defaults. +} + +@defmethod*[([(context) (is-a?/c wv-context%)])]{ +Returns the window context object associated with this window. +} + +@defmethod*[([(win-context) symbol?])]{ +Returns the symbolic context identifier derived from @racket[html-path]. +This value is typically used as the settings section for the window. +} + +@defmethod*[([(info) hash?])]{ +Returns a hash table with administrative information about the window. +The hash contains entries for at least @racket['wv-context], @racket['wv], +@racket['html-path], and @racket['elements]. +} + +@defmethod*[([(element [id symbol?]) any/c] + [(element [id symbol?] [type symbol?]) any/c])]{ +Returns the wrapper object for the DOM element with identifier @racket[id]. + +If the element has not been wrapped before, a new wrapper object is created and cached. +When @racket[type] is omitted, the method attempts to determine the HTML input type via +JavaScript. Depending on the resolved type, it creates an instance of a more specific +wrapper class such as @racket[wv-input/text%], @racket[wv-input/date%], +@racket[wv-input/number%], or falls back to @racket[wv-element%]. +} + +@defmethod*[([(moved [x exact-integer?] [y exact-integer?]) void?])]{ +Event hook called when the window has moved. +The default implementation stores the new position in the settings object. +Subclasses may override this method. +} + +@defmethod*[([(resized [width exact-integer?] [height exact-integer?]) void?])]{ +Event hook called when the window has been resized. +The default implementation stores the new size in the settings object. +Subclasses may override this method. +} + +@defmethod*[([(window-state-changed [state any/c]) any/c])]{ +Event hook called when the native window state changes, for example after show, +hide, or maximize notifications. The default implementation returns @racket[#t]. +} + +@defmethod*[([(page-loaded [ok? any/c]) any/c])]{ +Event hook called after the page load completes. The argument indicates whether the +load succeeded. The default implementation returns @racket[#t]. +} + +@defmethod*[([(can-close?) any/c])]{ +Event hook queried before closing the window. +If this method returns a true value, the default event handler closes the window. +The default implementation returns @racket[#t]. +} + +@defmethod*[([(closed) any/c])]{ +Event hook called after the window has been closed. +The default implementation returns @racket[#t]. +} + +@defmethod*[([(js-event [js-event hash?]) any/c])]{ +Handles a JavaScript-originated event. + +The default implementation looks up the wrapped element referenced by the event and +forwards the event to that element's dispatcher. If no matching element is known, +it returns @racket['wv-unhandled-js-event]. Subclasses may override this for +application-specific dispatch. +} + +@defmethod*[([(navigation-request [type symbol?] [url url?]) (or/c 'internal 'external)])]{ +Handles a navigation request. + +If the requested URL starts with the context base URL, the window navigates internally +using @racket[webview-set-url!] and returns @racket['internal]. Otherwise the URL is +opened externally using @racket[send-url] and the method returns @racket['external]. +} + +@defmethod*[([(add-class! [selector-or-id string?] [class string?]) this])]{ +Adds the CSS class @racket[class] to the elements selected by @racket[selector-or-id]. +Delegates to @racket[webview-add-class!]. +} + +@defmethod*[([(remove-class! [selector-or-id string?] [class string?]) this])]{ +Removes the CSS class @racket[class] from the elements selected by @racket[selector-or-id]. +Delegates to @racket[webview-remove-class!]. +} + +@defmethod*[([(devtools) this])]{ +Opens or activates the developer tools for the underlying webview. +} + +@defmethod*[([(move [x exact-integer?] [y exact-integer?]) this])]{ +Moves the native window to the given screen coordinates. +} + +@defmethod*[([(resize [width exact-integer?] [height exact-integer?]) this])]{ +Resizes the native window to the given dimensions. +} + +@defmethod*[([(close) this])]{ +Closes the native window. +} + +@defmethod*[([(bind! [selector string?] + [events (or/c symbol? (listof symbol?))] + [callback procedure?]) (listof any/c)])]{ +Binds one or more DOM events to all elements matched by @racket[selector]. + +This method delegates the JavaScript side of the binding to @racket[webview-bind!], +creates or reuses wrapper objects for the matched elements, and installs +@racket[callback] as event callback on each wrapper. The return value is the list of +matched element wrapper objects. +} + +@defmethod*[([(unbind! [selector string?] + [events (or/c symbol? (listof symbol?))]) any/c])]{ +Removes previously installed bindings for the selected elements and events. +This method delegates to @racket[webview-unbind!] and removes callbacks from the +corresponding cached wrapper objects. +} + +@defmethod*[([(file-dialog-done [flag symbol?] + [file any/c] + [dir any/c] + [filter any/c]) void?])]{ +Continuation hook used internally to resume a pending file or directory dialog. +Applications normally do not call this method directly. +} + +@defmethod*[([(choose-dir [title string?] [base-dir (or/c #f path-string?)]) + (or/c 'showing path-string? #f)])]{ +Shows a directory chooser. + +If the chooser is successfully shown, the method initially returns @racket['showing] +and later resumes with the selected directory path or @racket[#f] when the dialog is +canceled. If the dialog cannot be shown, it returns @racket[#f]. +Only one file or directory dialog can be active at a time. +} + +@defmethod*[([(file-open [title string?] + [base-dir (or/c #f path-string?)] + [filters any/c]) + (or/c 'showing list? #f)])]{ +Shows a file-open dialog. + +If the dialog is accepted, the resumed result is a list whose contents are derived from +the low-level file dialog result. If the dialog is canceled or cannot be shown, the +result is @racket[#f]. Only one file or directory dialog can be active at a time. +} + +@defmethod*[([(file-save [title string?] + [base-dir (or/c #f path-string?)] + [filters any/c]) + (or/c 'showing list? #f)])]{ +Shows a file-save dialog. + +If the dialog is accepted, the resumed result is a list whose contents are derived from +the low-level file dialog result. If the dialog is canceled or cannot be shown, the +result is @racket[#f]. Only one file or directory dialog can be active at a time. +} + +@defmethod*[([(message-done [event symbol?]) void?])]{ +Continuation hook used internally to resume a pending message box. +Applications normally do not call this method directly. +} + +@defmethod*[([(message [type symbol?] + [title string?] + [message string?] + [#:sub submessage string? ""]) + (or/c 'showing symbol? #f)])]{ +Shows a native message box. + +If the message box is shown successfully, the method initially returns @racket['showing] +and later resumes with the button result, such as @racket['msgbox-ok], +@racket['msgbox-cancel], @racket['msgbox-yes], or @racket['msgbox-no]. +If the message box cannot be shown, the method returns @racket[#f]. +Only one message box can be active at a time. +} + +@defmethod*[([(init-size) void?])]{ +Initializes the window position and size from the settings object. +If no persisted values are available, constructor arguments or module defaults are used. +} + +} + +@defproc[(root-file-not-found-handler [standard-file path-string?] + [not-found-handler procedure?]) + procedure?]{ +Creates a file-resolution procedure that can be used as a fallback handler for a webview +context. + +The returned procedure redirects requests for @tt{"/"} and, when needed, +@tt{"/index.html"} to @racket[standard-file]. For other missing files it either returns +the unresolved path unchanged or delegates to @racket[not-found-handler] when one is +supplied. +} + +@defthing[webview-version any/c]{ +The version identifier exported by the underlying webview binding. +}