# Lua Scripting Guide Mosis apps use Lua for scripting and interactivity. Each app runs in an isolated sandbox with access to Mosis-specific APIs. ## Getting Started Embed Lua directly in your RML files: ```xml
``` Or use external files: ```xml ``` ## Lua Basics If you're new to Lua, here's a quick primer: ### Variables ```lua -- Local variables (preferred) local name = "Mosis" local count = 42 local enabled = true local items = {"apple", "banana", "cherry"} -- Global variables (avoid when possible) globalVar = "accessible everywhere" ``` ### Functions ```lua -- Basic function function greet(name) return "Hello, " .. name .. "!" end -- Function with multiple returns function getPosition() return 100, 200 end local x, y = getPosition() -- Anonymous functions local double = function(n) return n * 2 end ``` ### Control Flow ```lua -- If statements if score > 100 then print("High score!") elseif score > 50 then print("Good job!") else print("Keep trying!") end -- Loops for i = 1, 10 do print(i) end for index, value in ipairs(items) do print(index, value) end while condition do -- loop body end ``` ### Tables ```lua -- Array-like table local colors = {"red", "green", "blue"} print(colors[1]) -- "red" (Lua is 1-indexed) -- Dictionary-like table local user = { name = "Alice", age = 25, premium = true } print(user.name) print(user["age"]) -- Mixed table local app = { name = "MyApp", version = "1.0", features = {"dark mode", "notifications"} } ``` ## DOM Manipulation Access and modify UI elements using the `document` object: ### Getting Elements ```lua -- By ID local button = document:GetElementById("my-button") -- By tag name local paragraphs = document:GetElementsByTagName("p") -- By class name local cards = document:GetElementsByClassName("card") ``` ### Modifying Content ```lua local element = document:GetElementById("message") -- Set inner content (HTML-like) element.inner_rml = "Hello!" -- Get inner content local content = element.inner_rml -- Set text only (safer, no HTML parsing) element:SetInnerRML("Plain text here") ``` ### Modifying Attributes ```lua local input = document:GetElementById("username") -- Get attribute local value = input:GetAttribute("value") -- Set attribute input:SetAttribute("placeholder", "Enter username") -- Remove attribute input:RemoveAttribute("disabled") ``` ### Modifying Styles ```lua local box = document:GetElementById("box") -- Set individual properties box.style.width = "200dp" box.style.backgroundColor = "#00d4ff" box.style.display = "none" -- hide element -- Read properties local width = box.style.width ``` ### Classes ```lua local element = document:GetElementById("panel") -- Add class element:SetClass("active", true) -- Remove class element:SetClass("active", false) -- Check class if element:IsClassSet("active") then print("Panel is active") end ``` ## Event Handling ### Inline Events ```xml ``` ### Event Listeners ```lua local button = document:GetElementById("my-button") -- Add listener button:AddEventListener("click", function(event) print("Button clicked!") end) -- Remove listener (need reference) local handler = function(event) print("Clicked") end button:AddEventListener("click", handler) button:RemoveEventListener("click", handler) ``` ### Event Object ```lua function handleEvent(event) -- Event type print(event.type) -- "click", "change", etc. -- Target element local target = event:GetCurrentElement() -- Mouse position (for mouse events) local x = event.parameters.mouse_x local y = event.parameters.mouse_y -- Stop propagation event:StopPropagation() end ``` ### Common Events | Event | Description | |-------|-------------| | `click` | Element clicked | | `dblclick` | Element double-clicked | | `mousedown` | Mouse button pressed | | `mouseup` | Mouse button released | | `mouseover` | Mouse enters element | | `mouseout` | Mouse leaves element | | `focus` | Element gains focus | | `blur` | Element loses focus | | `change` | Input value changed | | `submit` | Form submitted | | `keydown` | Key pressed | | `keyup` | Key released | ## Timers ### setTimeout ```lua -- Execute once after delay local timerId = setTimeout(function() print("Executed after 1 second") end, 1000) -- milliseconds -- Cancel timer clearTimeout(timerId) ``` ### setInterval ```lua -- Execute repeatedly local intervalId = setInterval(function() print("Tick") end, 1000) -- Cancel interval clearInterval(intervalId) ``` ## Storage Persist data between app sessions: ```lua -- Save data storage.set("username", "Alice") storage.set("settings", { darkMode = true, notifications = false }) -- Load data local username = storage.get("username") local settings = storage.get("settings") -- Delete data storage.remove("username") -- Clear all data storage.clear() ``` ## Navigation Navigate between screens in your app: ```lua -- Navigate to screen navigateTo("settings") -- loads assets/settings.rml -- Go back goBack() -- Go to home screen goHome() -- Replace current screen (no back) replaceTo("login") ``` ### Navigation Events ```lua -- Listen for navigation onNavigate(function(screenName) print("Navigated to: " .. screenName) end) -- Listen for back onBack(function() print("Going back") end) ``` ## HTTP Requests Make network requests (requires `network` permission): ```lua -- GET request http.get("https://api.example.com/data", function(response) if response.ok then local data = json.decode(response.body) print(data.message) else print("Error: " .. response.status) end end) -- POST request http.post("https://api.example.com/submit", { headers = { ["Content-Type"] = "application/json" }, body = json.encode({ name = "Alice", action = "subscribe" }) }, function(response) print("Status: " .. response.status) end) ``` ## JSON ```lua -- Parse JSON string local data = json.decode('{"name": "Alice", "age": 25}') print(data.name) -- Convert to JSON string local str = json.encode({ items = {"a", "b", "c"}, count = 3 }) ``` ## Date and Time ```lua -- Current timestamp local now = os.time() -- Format date local formatted = os.date("%Y-%m-%d %H:%M:%S", now) -- Parse date components local t = os.date("*t", now) print(t.year, t.month, t.day, t.hour, t.min, t.sec) ``` ## Utilities ### String Functions ```lua -- Concatenation local greeting = "Hello, " .. name .. "!" -- String functions string.upper("hello") -- "HELLO" string.lower("HELLO") -- "hello" string.sub("hello", 1, 3) -- "hel" string.find("hello", "ll") -- 3 string.gsub("hello", "l", "L") -- "heLLo" string.format("Score: %d", 100) -- "Score: 100" ``` ### Math Functions ```lua math.floor(3.7) -- 3 math.ceil(3.2) -- 4 math.round(3.5) -- 4 math.abs(-5) -- 5 math.min(1, 2, 3) -- 1 math.max(1, 2, 3) -- 3 math.random() -- 0-1 math.random(1, 6) -- 1-6 ``` ### Table Functions ```lua -- Insert table.insert(items, "new item") table.insert(items, 1, "at beginning") -- Remove table.remove(items) -- remove last table.remove(items, 1) -- remove first -- Sort table.sort(items) table.sort(items, function(a, b) return a > b end) -- descending -- Length local count = #items ``` ## Sandbox Restrictions For security, these are **NOT** available: - `os.execute`, `io.popen` - No shell commands - `loadfile`, `dofile` - No arbitrary file loading - `require` - No external modules (use `import` for app modules) - `debug` library - No debugging hooks - `rawget`, `rawset` - No metatable bypass ## Best Practices 1. **Use local variables** - Faster and prevents pollution 2. **Handle errors** - Use `pcall` for operations that might fail 3. **Clean up timers** - Clear intervals when navigating away 4. **Minimize DOM queries** - Cache element references 5. **Batch updates** - Group style changes together ### Error Handling ```lua local success, result = pcall(function() -- Code that might fail local data = json.decode(invalidJson) return data end) if success then print("Parsed:", result) else print("Error:", result) end ``` ### Module Pattern ```lua -- utils.lua local Utils = {} function Utils.formatCurrency(amount) return string.format("$%.2f", amount) end function Utils.capitalize(str) return str:sub(1,1):upper() .. str:sub(2) end return Utils ``` ```lua -- main.lua local Utils = import("utils") print(Utils.formatCurrency(19.99)) ``` ## Next Steps - [Permissions Guide](permissions.md) - Request device capabilities - [API Reference](../api/lua-api.md) - Complete API documentation - [Debugging Guide](debugging.md) - Debug your Lua code