| import AppKit |
| import Foundation |
|
|
| extension CanvasWindowController { |
| |
|
|
| static func sanitizeSessionKey(_ key: String) -> String { |
| let trimmed = key.trimmingCharacters(in: .whitespacesAndNewlines) |
| if trimmed.isEmpty { return "main" } |
| let allowed = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-+") |
| let scalars = trimmed.unicodeScalars.map { allowed.contains($0) ? Character($0) : "_" } |
| return String(scalars) |
| } |
|
|
| static func jsStringLiteral(_ value: String) -> String { |
| let data = try? JSONEncoder().encode(value) |
| return data.flatMap { String(data: $0, encoding: .utf8) } ?? "\"\"" |
| } |
|
|
| static func jsOptionalStringLiteral(_ value: String?) -> String { |
| guard let value else { return "null" } |
| return Self.jsStringLiteral(value) |
| } |
|
|
| static func storedFrameDefaultsKey(sessionKey: String) -> String { |
| "openclaw.canvas.frame.\(self.sanitizeSessionKey(sessionKey))" |
| } |
|
|
| static func loadRestoredFrame(sessionKey: String) -> NSRect? { |
| let key = self.storedFrameDefaultsKey(sessionKey: sessionKey) |
| guard let arr = UserDefaults.standard.array(forKey: key) as? [Double], arr.count == 4 else { return nil } |
| let rect = NSRect(x: arr[0], y: arr[1], width: arr[2], height: arr[3]) |
| if rect.width < CanvasLayout.minPanelSize.width || rect.height < CanvasLayout.minPanelSize.height { return nil } |
| return rect |
| } |
|
|
| static func storeRestoredFrame(_ frame: NSRect, sessionKey: String) { |
| let key = self.storedFrameDefaultsKey(sessionKey: sessionKey) |
| UserDefaults.standard.set( |
| [Double(frame.origin.x), Double(frame.origin.y), Double(frame.size.width), Double(frame.size.height)], |
| forKey: key) |
| } |
| } |
|
|