jsaddle-wkwebview 0.8.2.0 → 0.8.3.0
raw patch · 6 files changed
+118/−12 lines, 6 filesdep ~aeson
Dependency ranges changed: aeson
Files
- cbits-cocoa/AppDelegate.m +6/−1
- cbits-uikit/AppDelegate.m +8/−0
- cbits/WKWebView.m +47/−2
- jsaddle-wkwebview.cabal +2/−2
- src-ghc/Language/Javascript/JSaddle/WKWebView.hs +16/−1
- src/Language/Javascript/JSaddle/WKWebView/Internal.hs +39/−6
cbits-cocoa/AppDelegate.m view
@@ -22,7 +22,8 @@ if (self) { _handler = handler; NSRect contentSize = NSMakeRect(0.0, 500.0, 1000.0, 700.0);- NSUInteger windowStyleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;+ // TODO replace with once nix has newer Cocoa NSUInteger windowStyleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;+ NSUInteger windowStyleMask = NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; _window = [[NSWindow alloc] initWithContentRect:contentSize styleMask:windowStyleMask backing:NSBackingStoreBuffered defer:YES]; _window.backgroundColor = [NSColor whiteColor]; _window.title = progName;@@ -60,3 +61,7 @@ } } +BOOL openApp(NSURL * url) {+ NSWorkspace *workspace = [NSWorkspace sharedWorkspace];+ return [workspace openURL:url];+}
cbits-uikit/AppDelegate.m view
@@ -55,3 +55,11 @@ } } +BOOL openApp(NSURL * url) {+ UIApplication *app = [UIApplication sharedApplication];+ if ([app canOpenURL:url]) {+ [app openURL:url];+ return true;+ }+ return false;+}
cbits/WKWebView.m view
@@ -2,6 +2,8 @@ #import <Foundation/Foundation.h> #import <WebKit/WebKit.h> +BOOL openApp(NSURL * url);+ extern void jsaddleStart(HsStablePtr); extern void jsaddleResult(HsStablePtr, const char * _Nonnull result); @@ -37,6 +39,20 @@ jsaddleResult(self.resultHandler, [s UTF8String]); } +- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler+{+ NSURL *url = navigationAction.request.URL;++ if(!navigationAction.targetFrame && ![url.scheme isEqualToString:@"file"]) {+ if(openApp(url))+ decisionHandler(WKNavigationActionPolicyCancel);+ else+ decisionHandler(WKNavigationActionPolicyAllow);+ }+ else+ decisionHandler(WKNavigationActionPolicyAllow);+}+ @end void addJSaddleHandler(WKWebView *webView, HsStablePtr startHandler, HsStablePtr resultHandler) {@@ -46,10 +62,39 @@ } void evaluateJavaScript(WKWebView *webView, const char * _Nonnull js) {- [webView evaluateJavaScript:[NSString stringWithCString:js encoding:NSUTF8StringEncoding] completionHandler:NULL];+ NSString *jsString = [[NSString alloc] initWithCString:js encoding:NSUTF8StringEncoding];+ dispatch_async(dispatch_get_main_queue(), ^{+ [webView evaluateJavaScript:jsString completionHandler:NULL];+ [jsString release];+ }); } void loadHTMLString(WKWebView *webView, const char * _Nonnull html) {- [webView loadHTMLString:[NSString stringWithCString:html encoding:NSUTF8StringEncoding] baseURL:NULL];+ NSString *htmlString = [NSString stringWithCString:html encoding:NSUTF8StringEncoding];+ dispatch_async(dispatch_get_main_queue(), ^{+ [webView loadHTMLString:htmlString baseURL:NULL];+ }); }++const char * mainBundleResourcePathC() {+ NSBundle *main = [NSBundle mainBundle];+ if(!main) return NULL;+ NSString *path = main.resourcePath;+ if(!path) return NULL;+ return [path UTF8String];+}++void loadBundleFile(WKWebView *webView, const char * _Nonnull file, const char * _Nonnull allowing) {+ NSBundle *main = [NSBundle mainBundle];+ if(main) {+ NSString *path = main.resourcePath;+ if(path) {+ NSURL *fileUrl = [NSURL fileURLWithPath:[NSString stringWithFormat: @"%@/%@", path, [NSString stringWithCString:file encoding:NSUTF8StringEncoding]]];+ NSURL *allowingUrl = [NSURL fileURLWithPath:[NSString stringWithFormat: @"%@/%@", path, [NSString stringWithCString:allowing encoding:NSUTF8StringEncoding]]];+ [webView loadFileURL:fileUrl allowingReadAccessToURL:allowingUrl];+ }+ }+}++
jsaddle-wkwebview.cabal view
@@ -1,5 +1,5 @@ name: jsaddle-wkwebview-version: 0.8.2.0+version: 0.8.3.0 cabal-version: >=1.10 build-type: Simple license: MIT@@ -23,7 +23,7 @@ Language.Javascript.JSaddle.WKWebView Language.Javascript.JSaddle.WKWebView.Internal build-depends:- aeson >=0.8.0.2 && <1.1,+ aeson >=0.8.0.2 && <1.2, base <5, bytestring >=0.10.6.0 && <0.11, jsaddle >= 0.8.0.0 && <0.9
src-ghc/Language/Javascript/JSaddle/WKWebView.hs view
@@ -1,10 +1,14 @@ module Language.Javascript.JSaddle.WKWebView ( jsaddleMain+ , jsaddleMainFile , WKWebView(..) , run+ , runFile+ , mainBundleResourcePath ) where -import Language.Javascript.JSaddle.WKWebView.Internal (jsaddleMain, WKWebView(..))+import Data.ByteString (ByteString)+import Language.Javascript.JSaddle.WKWebView.Internal (jsaddleMain, jsaddleMainFile, WKWebView(..), mainBundleResourcePath) import System.Environment (getProgName) import Foreign.C.String (CString, withCString) import Foreign.StablePtr (StablePtr, newStablePtr)@@ -12,8 +16,19 @@ foreign import ccall runInWKWebView :: StablePtr (WKWebView -> IO ()) -> CString -> IO () +-- | Run JSaddle in a WKWebView run :: JSM () -> IO () run f = do handler <- newStablePtr (jsaddleMain f)+ progName <- getProgName+ withCString progName $ runInWKWebView handler++-- | Run JSaddle in a WKWebView first loading the specified file+-- from the mainBundle (relative to the resourcePath).+runFile :: ByteString -- ^ The file to navigate to.+ -> ByteString -- ^ The path to allow read access to.+ -> JSM () -> IO ()+runFile url allowing f = do+ handler <- newStablePtr (jsaddleMainFile url allowing f) progName <- getProgName withCString progName $ runInWKWebView handler
src/Language/Javascript/JSaddle/WKWebView/Internal.hs view
@@ -1,19 +1,23 @@ {-# LANGUAGE ForeignFunctionInterface, OverloadedStrings #-} module Language.Javascript.JSaddle.WKWebView.Internal ( jsaddleMain+ , jsaddleMainFile , WKWebView(..)+ , mainBundleResourcePath ) where import Control.Monad (void, join)-import Control.Concurrent (forkIO)+import Control.Concurrent (forkIO, forkOS)+import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar) import Data.Monoid ((<>)) import Data.ByteString (useAsCString, packCString)+import qualified Data.ByteString as BS (ByteString) import Data.ByteString.Lazy (ByteString, toStrict, fromStrict) import Data.Aeson (encode, decode) import Foreign.C.String (CString)-import Foreign.Ptr (Ptr)+import Foreign.Ptr (Ptr, nullPtr) import Foreign.StablePtr (StablePtr, newStablePtr, deRefStablePtr) import Language.Javascript.JSaddle (Results, JSM)@@ -27,21 +31,43 @@ foreign export ccall withWebView :: WKWebView -> StablePtr (WKWebView -> IO ()) -> IO () foreign import ccall addJSaddleHandler :: WKWebView -> StablePtr (IO ()) -> StablePtr (Results -> IO ()) -> IO () foreign import ccall loadHTMLString :: WKWebView -> CString -> IO ()+foreign import ccall loadBundleFile :: WKWebView -> CString -> CString -> IO () foreign import ccall evaluateJavaScript :: WKWebView -> CString -> IO ()+foreign import ccall mainBundleResourcePathC :: IO CString +-- | Run JSaddle in WKWebView jsaddleMain :: JSM () -> WKWebView -> IO () jsaddleMain f webView = do+ jsaddleMain' f webView $+ useAsCString (toStrict indexHtml) $ loadHTMLString webView++-- | Run JSaddle in a WKWebView first loading the specified file+-- from the mainBundle (relative to the resourcePath).+jsaddleMainFile :: BS.ByteString -- ^ The file to navigate to.+ -> BS.ByteString -- ^ The path to allow read access to.+ -> JSM () -> WKWebView -> IO ()+jsaddleMainFile url allowing f webView = do+ jsaddleMain' f webView $+ useAsCString url $ \u ->+ useAsCString allowing $ \a ->+ loadBundleFile webView u a++jsaddleMain' :: JSM () -> WKWebView -> IO () -> IO ()+jsaddleMain' f webView loadHtml = do+ ready <- newEmptyMVar+ (processResult, start) <- runJavaScript (\batch -> useAsCString (toStrict $ "runJSaddleBatch(" <> encode batch <> ");") $ evaluateJavaScript webView) f - startHandler <- newStablePtr (void $ forkIO start)+ startHandler <- newStablePtr (putMVar ready ()) resultHandler <- newStablePtr processResult addJSaddleHandler webView startHandler resultHandler-- useAsCString (toStrict indexHtml) $ loadHTMLString webView- useAsCString (toStrict jsaddleJs) $ evaluateJavaScript webView+ loadHtml+ void . forkOS $ do+ takeMVar ready+ useAsCString (toStrict jsaddleJs) (evaluateJavaScript webView) >> void (forkIO start) jsaddleStart :: StablePtr (IO ()) -> IO () jsaddleStart ptrHandler = join (deRefStablePtr ptrHandler)@@ -79,3 +105,10 @@ \<body>\n\ \</body>\n\ \</html>"++mainBundleResourcePath :: IO (Maybe BS.ByteString)+mainBundleResourcePath = do+ bs <- mainBundleResourcePathC+ if bs == nullPtr+ then return Nothing+ else Just <$> packCString bs