140 lines
5.4 KiB
Swift
140 lines
5.4 KiB
Swift
import Cocoa
|
|
@preconcurrency import WebKit
|
|
|
|
class ViewController: NSViewController, WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler {
|
|
@IBOutlet var webView: WKWebView!
|
|
|
|
var windowTitle: String = "Window Title"
|
|
|
|
override func loadView() {
|
|
super.loadView()
|
|
|
|
let configUrl = Bundle.main.url(forResource: "application_config", withExtension: "json")!
|
|
let configContents = try! Data(contentsOf: configUrl);
|
|
let configParsed = try! JSONSerialization.jsonObject(with: configContents, options: [])
|
|
|
|
var width = 480
|
|
var height = 360
|
|
var background = NSColor.black.cgColor
|
|
if let dict = configParsed as? [String: Any] {
|
|
if let title = dict["title"] as? String {
|
|
self.windowTitle = title
|
|
}
|
|
if let number = dict["width"] as? Int {
|
|
width = number
|
|
}
|
|
if let number = dict["height"] as? Int {
|
|
height = number
|
|
}
|
|
if let color = dict["background"] as? [Int] {
|
|
background = NSColor(
|
|
red: CGFloat(color[0]) / 255.0,
|
|
green: CGFloat(color[1]) / 255.0,
|
|
blue: CGFloat(color[2]) / 255.0,
|
|
alpha: CGFloat(color[3])
|
|
).cgColor
|
|
}
|
|
}
|
|
view.wantsLayer = true
|
|
view.layer?.backgroundColor = background
|
|
view.frame = CGRect(x: 0, y: 0, width: width, height: height)
|
|
|
|
webView.isHidden = true
|
|
webView.navigationDelegate = self
|
|
webView.uiDelegate = self
|
|
webView.configuration.userContentController.add(self, name: "download")
|
|
webView.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
|
|
|
|
#if DEBUG
|
|
if #available(macOS 13.3, *) {
|
|
webView.isInspectable = true
|
|
}
|
|
webView.configuration.preferences.setValue(true, forKey: "developerExtrasEnabled")
|
|
#endif
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
let url = Bundle.main.url(forResource: "index", withExtension: "html")!
|
|
webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
|
|
}
|
|
|
|
override func viewDidAppear() {
|
|
super.viewDidAppear()
|
|
view.window?.title = windowTitle
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
|
// The packager will use window.ExternalDownloadHelper instead of native JS file downloads.
|
|
// We use this because older versions of macOS's WKWebView do not handle file downloads
|
|
// properly or at all.
|
|
webView.evaluateJavaScript("""
|
|
window.ExternalDownloadHelper = {
|
|
download: (filename, blob) => {
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
const array = Array.from(new Uint8Array(reader.result));
|
|
webkit.messageHandlers.download.postMessage({
|
|
name: filename,
|
|
data: array
|
|
});
|
|
};
|
|
reader.onerror = () => {
|
|
console.error(reader.error);
|
|
};
|
|
reader.readAsArrayBuffer(blob);
|
|
}
|
|
};
|
|
""")
|
|
webView.isHidden = false
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) {
|
|
// Used by list import.
|
|
let panel = NSOpenPanel()
|
|
panel.canChooseFiles = true
|
|
panel.canChooseDirectories = false
|
|
panel.allowsMultipleSelection = parameters.allowsMultipleSelection
|
|
panel.allowedFileTypes = ["txt", "csv", "tsv"]
|
|
panel.allowsOtherFileTypes = true
|
|
panel.begin { (result) -> Void in
|
|
if result == NSApplication.ModalResponse.OK, let url = panel.url {
|
|
completionHandler([url])
|
|
} else {
|
|
completionHandler(nil)
|
|
}
|
|
}
|
|
}
|
|
|
|
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
|
// Used by window.ExternalDownloadHelper which is used by list export.
|
|
if message.name == "download",
|
|
let body = message.body as? NSDictionary,
|
|
let name = body["name"] as? NSString,
|
|
let rawData = body["data"] as? [UInt8] {
|
|
let panel = NSSavePanel()
|
|
panel.allowsOtherFileTypes = true
|
|
panel.nameFieldStringValue = name as String
|
|
panel.allowedFileTypes = ["txt"]
|
|
panel.begin { (result) -> Void in
|
|
if result == NSApplication.ModalResponse.OK, let url = panel.url {
|
|
let data = Data(rawData)
|
|
try! data.write(to: url)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(macOS 12.0, *)
|
|
func webView(_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin, initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType, decisionHandler: @escaping (WKPermissionDecision) -> Void) {
|
|
// macOS will already show a permission prompt.
|
|
// This code prevents WKWebView from showing an additional permission prompt each time.
|
|
decisionHandler(WKPermissionDecision.grant)
|
|
}
|
|
|
|
func webViewDidClose(_ webView: WKWebView) {
|
|
// Implements window.close()
|
|
self.view.window?.close();
|
|
}
|
|
}
|