PyPositron Docs

HTMLWindow Class

The HTMLWindow class provides JavaScript window object functionality within PyPositron. It's available as ui.htmlwindow in your main function and represents the browser window that contains your HTML document. This class provides access to browser APIs, dialog methods, timing functions, and window management capabilities.

Overview

The HTMLWindow class is your gateway to browser-specific functionality in PyPositron. It allows you to:

  • Display dialog boxes (alert, confirm, prompt)
  • Manage timers and animations
  • Control window properties and behavior
  • Access browser objects (navigator, location, history)
  • Handle window events and navigation

Properties

Window State

Window Dimensions

Window Position

Scroll Position

Browser Objects

Window Hierarchy

Storage

Methods

Dialog Methods

  • alert(message: str): Displays an alert box with a message and an OK button. W3Schools Reference | MDN Reference
  • confirm(message: str) -> bool: Displays a dialog box with a message and an OK and a Cancel button. Returns True if OK is clicked, False if Cancel is clicked. W3Schools Reference | MDN Reference
  • prompt(message: str, default_value: str = '') -> str: Displays a dialog box that prompts the visitor for input. Returns the input string or None if cancelled. W3Schools Reference | MDN Reference

Timing Methods

Animation

  • requestAnimationFrame(callback) -> int: Requests the browser to call a function to update an animation before the next repaint. W3Schools Reference | MDN Reference

Window Management

Window Positioning and Sizing

Scrolling

Event Handling

Utility Methods

CSS and Styling

Selection and Encoding

Usage Examples

Dialog Interactions

def main(ui):
    def show_welcome():
        ui.htmlwindow.alert("Welcome to PyPositron!")
        
        if ui.htmlwindow.confirm("Would you like to continue?"):
            name = ui.htmlwindow.prompt("What's your name?", "User")
            if name:
                ui.htmlwindow.alert(f"Hello, {name}!")
                return name
        return None
    
    # Trigger welcome dialog
    welcome_btn = ui.document.getElementById("welcomeBtn")
    if welcome_btn:
        welcome_btn.addEventListener("click", show_welcome)

Timer and Delays

def main(ui):
    status_div = ui.document.getElementById("status")
    
    def show_message(text, duration=3000):
        status_div.innerText = text
        status_div.style.opacity = "1"
        
        # Auto-hide after duration
        def hide_message():
            status_div.style.opacity = "0"
        
        ui.htmlwindow.setTimeout(hide_message, duration)
    
    def start_countdown():
        count = 5
        countdown_display = ui.document.getElementById("countdown")
        
        def update_countdown():
            nonlocal count
            if count > 0:
                countdown_display.innerText = f"Starting in {count}..."
                count -= 1
                ui.htmlwindow.setTimeout(update_countdown, 1000)
            else:
                countdown_display.innerText = "Started!"
                show_message("Process completed!", 2000)
        
        update_countdown()
    
    start_btn = ui.document.getElementById("startBtn")
    if start_btn:
        start_btn.addEventListener("click", start_countdown)

Auto-save with Intervals

def main(ui):
    editor = ui.document.getElementById("editor")
    save_status = ui.document.getElementById("saveStatus")
    auto_save_interval = None
    
    def save_content():
        content = editor.value
        # Simulate saving to localStorage
        ui.htmlwindow.localStorage.setItem("draft", content)
        save_status.innerText = "Saved"
        save_status.style.color = "green"
        
        # Clear status after 2 seconds
        ui.htmlwindow.setTimeout(lambda: setattr(save_status, 'innerText', ''), 2000)
    
    def start_auto_save():
        nonlocal auto_save_interval
        # Save every 30 seconds
        auto_save_interval = ui.htmlwindow.setInterval(save_content, 30000)
        save_status.innerText = "Auto-save enabled"
    
    def stop_auto_save():
        nonlocal auto_save_interval
        if auto_save_interval:
            ui.htmlwindow.clearInterval(auto_save_interval)
            auto_save_interval = None
            save_status.innerText = "Auto-save disabled"
    
    # Load saved content on startup
    if editor:
        saved_content = ui.htmlwindow.localStorage.getItem("draft")
        if saved_content:
            editor.value = saved_content
        
        # Start auto-save when user types
        def on_input():
            if not auto_save_interval:
                start_auto_save()
        
        editor.addEventListener("input", on_input)
    
    # Manual save button
    save_btn = ui.document.getElementById("saveBtn")
    if save_btn:
        save_btn.addEventListener("click", save_content)

Window Information Display

def main(ui):
    def update_window_info():
        info_div = ui.document.getElementById("windowInfo")
        
        info_html = f"""
        <h3>Window Information</h3>
        <p><strong>Inner Size:</strong> {ui.htmlwindow.innerWidth} x {ui.htmlwindow.innerHeight}</p>
        <p><strong>Outer Size:</strong> {ui.htmlwindow.outerWidth} x {ui.htmlwindow.outerHeight}</p>
        <p><strong>Screen Position:</strong> ({ui.htmlwindow.screenX}, {ui.htmlwindow.screenY})</p>
        <p><strong>Scroll Position:</strong> ({ui.htmlwindow.scrollX}, {ui.htmlwindow.scrollY})</p>
        <p><strong>User Agent:</strong> {ui.htmlwindow.navigator.userAgent}</p>
        <p><strong>Online:</strong> {'Yes' if ui.htmlwindow.navigator.onLine else 'No'}</p>
        """
        
        info_div.innerHTML = info_html
    
    # Update on window resize
    ui.htmlwindow.addEventListener("resize", update_window_info)
    ui.htmlwindow.addEventListener("scroll", update_window_info)
    
    # Initial update
    update_window_info()
    
    # Refresh button
    refresh_btn = ui.document.getElementById("refreshInfo")
    if refresh_btn:
        refresh_btn.addEventListener("click", update_window_info)

Smooth Scrolling

def main(ui):
    def smooth_scroll_to_top():
        def scroll_step():
            current_scroll = ui.htmlwindow.scrollY
            if current_scroll > 0:
                ui.htmlwindow.scrollTo(0, current_scroll - 50)
                ui.htmlwindow.requestAnimationFrame(scroll_step)
        
        scroll_step()
    
    def scroll_to_element(element_id):
        element = ui.document.getElementById(element_id)
        if element:
            element.scrollIntoView(True)
    
    # Scroll to top button
    top_btn = ui.document.getElementById("scrollTopBtn")
    if top_btn:
        top_btn.addEventListener("click", smooth_scroll_to_top)
    
    # Navigation links
    nav_links = ui.document.getElementsByClassName("nav-link")
    for link in nav_links:
        target_id = link.getAttribute("data-target")
        if target_id:
            link.addEventListener("click", lambda: scroll_to_element(target_id))

Responsive Design Helpers

def main(ui):
    def check_responsive_breakpoint():
        width = ui.htmlwindow.innerWidth
        
        if width >= 1200:
            return "xl"
        elif width >= 992:
            return "lg"
        elif width >= 768:
            return "md"
        elif width >= 576:
            return "sm"
        else:
            return "xs"
    
    def apply_responsive_layout():
        breakpoint = check_responsive_breakpoint()
        body = ui.document.body
        
        # Remove existing breakpoint classes
        class_list = body.className.split()
        class_list = [cls for cls in class_list if not cls.startswith("bp-")]
        
        # Add current breakpoint class
        class_list.append(f"bp-{breakpoint}")
        body.className = " ".join(class_list)
        
        # Show current breakpoint
        breakpoint_display = ui.document.getElementById("currentBreakpoint")
        if breakpoint_display:
            breakpoint_display.innerText = f"Current breakpoint: {breakpoint}"
    
    # Apply layout on resize
    ui.htmlwindow.addEventListener("resize", apply_responsive_layout)
    
    # Initial layout
    apply_responsive_layout()
    
    # Media query matching example
    def setup_media_queries():
        mobile_query = ui.htmlwindow.matchMedia("(max-width: 767px)")
        
        def handle_mobile_change(mql):
            mobile_nav = ui.document.getElementById("mobileNav")
            desktop_nav = ui.document.getElementById("desktopNav")
            
            if mql.matches:
                # Mobile view
                if mobile_nav:
                    mobile_nav.style.display = "block"
                if desktop_nav:
                    desktop_nav.style.display = "none"
            else:
                # Desktop view
                if mobile_nav:
                    mobile_nav.style.display = "none"
                if desktop_nav:
                    desktop_nav.style.display = "block"
        
        mobile_query.addEventListener("change", handle_mobile_change)
        handle_mobile_change(mobile_query)  # Initial check
    
    setup_media_queries()

Print Functionality

def main(ui):
    def prepare_for_print():
        # Hide non-printable elements
        no_print_elements = ui.document.getElementsByClassName("no-print")
        for element in no_print_elements:
            element.style.display = "none"
        
        # Add print-specific styling
        print_style = ui.document.createElement("style")
        print_style.innerHTML = """
        @media print {
            body { font-size: 12pt; }
            .print-only { display: block !important; }
            .no-print { display: none !important; }
        }
        """
        ui.document.head.appendChild(print_style)
    
    def print_page():
        prepare_for_print()
        ui.htmlwindow.print()
    
    print_btn = ui.document.getElementById("printBtn")
    if print_btn:
        print_btn.addEventListener("click", print_page)

Best Practices

  1. Handle dialog return values: Always check return values from confirm() and prompt() methods.

  2. Clean up timers: Always clear intervals and timeouts when they're no longer needed to prevent memory leaks.

  3. Use requestAnimationFrame for animations: For smooth animations, prefer requestAnimationFrame() over setTimeout().

  4. Check window properties safely: Some window properties may not be available in all contexts.

  5. Responsive design: Use window dimension properties and media queries to create responsive layouts.

  6. Save timer IDs: Store timer IDs returned by setTimeout() and setInterval() so you can clear them later.

# Good practice example
def main(ui):
    timer_id = None
    
    def start_timer():
        nonlocal timer_id
        if timer_id:
            ui.htmlwindow.clearInterval(timer_id)
        timer_id = ui.htmlwindow.setInterval(update_function, 1000)
    
    def stop_timer():
        nonlocal timer_id
        if timer_id:
            ui.htmlwindow.clearInterval(timer_id)
            timer_id = None

Common Window Events

You can listen for these events on the window object:

  • "resize": Window is resized
  • "scroll": Window is scrolled
  • "beforeunload": Before the window unloads
  • "load": Window has finished loading
  • "focus": Window gains focus
  • "blur": Window loses focus

Related Classes