Skip to content

Latest commit

 

History

History
449 lines (342 loc) · 10.5 KB

File metadata and controls

449 lines (342 loc) · 10.5 KB

Ring WebView Usage Guide

This comprehensive guide demonstrates how to use the Ring WebView library to build desktop applications with HTML/CSS/JavaScript frontends and Ring backends.

Quick Start

Every WebView application follows this basic pattern:

load "webview.ring"

# Create and configure the webview
oWebView = new WebView()
oWebView {
    setTitle("My Application")
    setSize(800, 600, WEBVIEW_HINT_NONE)
    setHtml(`
        <!DOCTYPE html>
        <html>
        <head><title>My App</title></head>
        <body>
            <h1>Hello, Ring WebView!</h1>
            <button onclick="alert('Hello from JavaScript!')">Click Me</button>
        </body>
        </html>
    `)
    run()
}

Configuration

Global Configuration

The WebView library uses a global configuration object that you can customize before creating instances:

# Customize global configuration before creating instances
aWebViewConfig = [
    :debug = false,    # Enable/disable debug mode (default: true)
    :window = NULL    # Parent window handle (default: NULL for new window)
]

Window Management

oWebView = new WebView()

# Window properties
oWebView.setTitle("My Application")
oWebView.setSize(800, 600, WEBVIEW_HINT_NONE)  # width, height, hints

# Get native window handle (for platform integration)
nativeWindow = oWebView.getWindow()

Content Loading

HTML Content

Set HTML content directly:

oWebView.setHtml(`
    <!DOCTYPE html>
    <html>
    <head><title>My App</title></head>
    <body>
        <h1>Welcome to Ring WebView</h1>
        <p>This content is generated by Ring!</p>
    </body>
    </html>
`)

Local Files

Load HTML from local files:

# Load HTML content from file
htmlContent = read("assets/index.html")
oWebView.setHtml(htmlContent)

Navigate to local files:

# Navigate to a local file URL
oWebView.navigate("file:///path/to/your/file.html")

Remote URLs

Navigate to websites:

# Navigate to a URL
oWebView.navigate("https://www.example.com")

JavaScript Integration

Calling Ring from JavaScript

Expose Ring functions to JavaScript using the bind() method:

load "webview.ring"
load "simplejson.ring"

# Global variables
oWebView = NULL
# Define functions to expose to JavaScript
aBindList = [
    ["sayHello", :handleGreeting],
    ["calculate", :doMath]
]

func main()
    oWebView = new WebView()
    
    oWebView {
        setTitle("Ring-JavaScript Communication")
        setSize(600, 400, WEBVIEW_HINT_NONE)
        
        setHtml(`
            <!DOCTYPE html>
            <html>
            <head><title>Communication Demo</title></head>
            <body>
                <h1>Ring-JavaScript Communication</h1>
                <button onclick="callRingHello()">Say Hello</button>
                <button onclick="callRingCalc()">Calculate</button>
                <div id="result"></div>
                
                <script>
                async function callRingHello() {
                    try {
                        const response = await window.sayHello('World');
                        document.getElementById('result').innerText = response;
                    } catch (error) {
                        console.error('Error:', error);
                    }
                }
                
                async function callRingCalc() {
                    try {
                        const result = await window.calculate(5, 3, 'add');
                        document.getElementById('result').innerText = 'Result: ' + result;
                    } catch (error) {
                        console.error('Error:', error);
                    }
                }
                </script>
            </body>
            </html>
        `)
        
        run()
    }

# Ring functions called from JavaScript
func handleGreeting(id, req)
    # req is a JSON string: ["World"]
    see "Greeting requested: " + req + nl
    
    # Send response back to JavaScript
    oWebView.wreturn(id, WEBVIEW_ERROR_OK, '"Hello from Ring!"')

func doMath(id, req)
    # Parse arguments from JSON
    aArgs = json_decode(req)  # Expected format: [5, 3, "add"]
    n1 = number(aArgs[1])
    n2 = number(aArgs[2])
    operation = aArgs[3]
    
    switch operation
    on "add"
        result = n1 + n2
    on "subtract"
        result = n1 - n2
    on "multiply"
        result = n1 * n2
    on "divide"
        result = n1 / n2
    off
    
    oWebView.wreturn(id, WEBVIEW_ERROR_OK, string(result))

Binding Object Methods

Bind methods from Ring objects to JavaScript:

# Usage
oCounter = new Counter()
oWebView.bind(oCounter, [
    ["increment", :increment],
    ["decrement", :decrement],
    ["getValue", :getValue]
])

class Counter
    value = 0
    
    func increment(id, req)
        self.value++
        oWebView.wreturn(id, WEBVIEW_ERROR_OK, string(self.value))
    
    func decrement(id, req)
        self.value--
        oWebView.wreturn(id, WEBVIEW_ERROR_OK, string(self.value))
    
    func getValue(id, req)
        oWebView.wreturn(id, WEBVIEW_ERROR_OK, string(self.value))

Anonymous Function Binding

Bind anonymous functions directly:

# Bind an anonymous function
oWebView.bind("showAlert", func (id, req) {
    see "Anonymous function called: " + req + nl
    oWebView.wreturn(id, WEBVIEW_ERROR_OK, '"Message received!"')
})

Using bindMany()

The bindMany() method allows binding multiple functions at once:

# Global binding list (automatically used if it exists)
aBindList = [
    ["simpleFunc", :simpleFunction],
    [oMyObject, [
        ["objMethod1", :method1],
        ["objMethod2", :method2]
    ]]
]

# Or bind manually
oWebView.bindMany(aBindList)

JavaScript from Ring

Executing JavaScript

Execute JavaScript code from Ring:

# Simple JavaScript execution
oWebView.evalJS("alert('Hello from Ring!');")

# Update DOM elements
oWebView.evalJS("document.getElementById('status').innerText = 'Updated!';")

# Call JavaScript functions
oWebView.evalJS("myJavaScriptFunction('argument');")

Injecting JavaScript

Inject JavaScript to run before page loads:

# Inject JavaScript that runs before the main content
oWebView.injectJS("
    window.myGlobalVar = 'Hello from injected JS!';
    console.log('Injected JS executed');
")

Main Thread Dispatch

Execute Ring code on the main UI thread:

# Dispatch code to main thread
oWebView.dispatch("updateUI()")

func updateUI()
    # This runs on the main thread
    oWebView.evalJS("document.getElementById('counter').innerText = 'Updated';")

Function Parameters and Return Values

Parameter Passing

JavaScript calls to Ring functions receive two parameters:

  • id: Callback ID for sending responses back to JavaScript
  • req: JSON string containing arguments from JavaScript
func myFunction(id, req)
    # Parse JSON arguments
    aArgs = json_decode(req)  # Converts JSON string to Ring list
    
    # Access arguments
    arg1 = aArgs[1]
    arg2 = aArgs[2]
    
    # Process the request...
    
    # Send response back to JavaScript
    oWebView.wreturn(id, WEBVIEW_ERROR_OK, '"Response from Ring"')

Return Values

Always use wreturn() to send responses back to JavaScript:

# String response
oWebView.wreturn(id, WEBVIEW_ERROR_OK, '"Hello from Ring!"')

# Number response
oWebView.wreturn(id, WEBVIEW_ERROR_OK, string(42))

# JSON response
oWebView.wreturn(id, WEBVIEW_ERROR_OK, '{"success": true, "data": "value"}')

Complete Examples

Counter Application

load "webview.ring"

oWebView = NULL

func main()
    oWebView = new WebView()
    oWebView {
        setTitle("Counter Example")
        setSize(400, 300, WEBVIEW_HINT_NONE)
        
        # Bind counter methods
        bind(new Counter, [
            ["increment", :increment]
        ])
        
        setHtml(`
            <!DOCTYPE html>
            <html>
            <head><title>Counter</title></head>
            <body>
                <h1>Counter: <span id="counter">0</span></h1>
                <button onclick="window.increment()">Increment</button>
            </body>
            </html>
        `)
        
        run()
    }

class Counter
    value = 0
    
    func increment(id, req)
        self.value++
        # Update UI and send response
        oWebView.evalJS("document.getElementById('counter').innerText = " + string(self.value))
        oWebView.wreturn(id, WEBVIEW_ERROR_OK, "")

Form Handler

load "webview.ring"
load "simplejson.ring"

# Global variable to hold the WebView instance.
oWebView = NULL

func main()
    oWebView = new WebView()
    oWebView {
        setTitle("Form Example")
        setSize(500, 400, WEBVIEW_HINT_NONE)
        
        bind("submitForm", :handleForm)
        
        setHtml(`
            <!DOCTYPE html>
            <html>
            <head><title>Contact Form</title></head>
            <body>
                <h1>Contact Us</h1>
                <form name="contactForm">
                    <input type="text" name="name" placeholder="Your Name" required>
                    <input type="email" name="email" placeholder="Your Email" required>
                    <button type="button" onclick="submitFormData()">Submit</button>
                </form>
                <div id="response"></div>
                
                <script>
                async function submitFormData() {
                    const form = document.forms.contactForm;
                    const formData = [
                        form.name.value,
                        form.email.value
                    ];
                    
                    try {
                        const result = await window.submitForm(formData);
                        document.getElementById('response').innerText = result;
                    } catch (error) {
                        document.getElementById('response').innerText = 'Error: ' + error;
                    }
                }
                </script>
            </body>
            </html>
        `)
        
        run()
    }

func handleForm(id, req)
    # Parse form data from JSON
    aData = json_decode(req)
    ? aData
    name = aData[1][1]
    email = aData[1][2]
    
    see "Form submitted - Name: " + name + ", Email: " + email + nl
    
    # Process form (save to database, send email, etc.)
    
    oWebView.wreturn(id, WEBVIEW_ERROR_OK, '"Form submitted successfully!"')

Debug Mode

Enable debug mode to get detailed logging:

aWebViewConfig[:debug] = true