mirror of
https://github.com/HackPlan/quark-shell-mac.git
synced 2026-06-17 08:29:41 +08:00
863 lines
28 KiB
Objective-C
863 lines
28 KiB
Objective-C
//
|
|
// QSHWebViewDelegate.m
|
|
// quark-shell
|
|
//
|
|
// Created by Xhacker Liu on 3/31/14.
|
|
// Copyright (c) 2014 Xhacker. All rights reserved.
|
|
//
|
|
|
|
#import "QSHWebViewDelegate.h"
|
|
#import "QSHPreferencesViewController.h"
|
|
#import "QSHWebViewWindowController.h"
|
|
#import <MASPreferences/MASPreferences.h>
|
|
#import <Sparkle/Sparkle.h>
|
|
#import <ISO8601DateFormatter.h>
|
|
#import <StartAtLoginController.h>
|
|
#import "WKWebViewJavascriptBridge.h"
|
|
#import <GCDWebServer/GCDWebServer.h>
|
|
#import <AVFoundation/AVFoundation.h>
|
|
#import "NSArray+isIncludeString.h"
|
|
|
|
static const NSInteger kPreferencesDefaultHeight = 192;
|
|
|
|
@interface QSHWebViewDelegate () <NSUserNotificationCenterDelegate, WebPolicyDelegate> {
|
|
NSString *appVersion;
|
|
NSString *appBundleVersion;
|
|
NSString *platform;
|
|
AVAudioPlayer *_audioPlayer;
|
|
|
|
BOOL debug;
|
|
}
|
|
|
|
@property (nonatomic) MASPreferencesWindowController *preferencesWindowController;
|
|
@property (nonatomic) NSMutableArray *windows;
|
|
@property (nonatomic) NSMutableArray *prefWindows;
|
|
|
|
@end
|
|
|
|
@implementation QSHWebViewDelegate
|
|
|
|
+ (void)initialize
|
|
{
|
|
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitDeveloperExtras"];
|
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
}
|
|
|
|
+ (NSURL *)getFolderURL
|
|
{
|
|
NSURL *folderURL = [[NSUserDefaults standardUserDefaults] URLForKey:@"folder"];
|
|
if (folderURL){
|
|
return [folderURL absoluteURL];
|
|
}
|
|
return [[NSBundle mainBundle] resourceURL];
|
|
}
|
|
|
|
+ (NSURL *)getRootURL
|
|
{
|
|
NSURL *indexURL = [[NSUserDefaults standardUserDefaults] URLForKey:@"indexPath"];
|
|
if ( indexURL != nil && [[indexURL absoluteString] containsString:@"http"] ){
|
|
return indexURL;
|
|
}
|
|
NSURL *folderURL = [[NSUserDefaults standardUserDefaults] URLForKey:@"folder"];
|
|
if (folderURL){
|
|
return [folderURL absoluteURL];
|
|
}
|
|
return [[NSBundle mainBundle] resourceURL];
|
|
}
|
|
|
|
+ (NSURL *)getIndexURL
|
|
{
|
|
NSURL *folderURL = [[NSUserDefaults standardUserDefaults] URLForKey:@"folder"];
|
|
NSURL *indexURL = [[NSUserDefaults standardUserDefaults] URLForKey:@"indexPath"];
|
|
if (folderURL == nil){
|
|
folderURL = [[NSBundle mainBundle] resourceURL];
|
|
}
|
|
if (indexURL == nil){
|
|
indexURL = [NSURL URLWithString:@"index.html"];
|
|
}
|
|
if ( [[indexURL absoluteString] containsString:@"http"] ){
|
|
return indexURL;
|
|
}
|
|
return [[folderURL absoluteURL] URLByAppendingPathComponent:[indexURL absoluteString] ];
|
|
}
|
|
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
if (self) {
|
|
self.windows = [[NSMutableArray alloc] init];
|
|
self.prefWindows = [[NSMutableArray alloc] init];
|
|
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
|
|
appVersion = [infoDictionary objectForKey:@"CFBundleShortVersionString"];
|
|
appBundleVersion = [infoDictionary objectForKey:@"CFBundleVersion"];
|
|
|
|
platform = @"mac";
|
|
}
|
|
return self;
|
|
}
|
|
|
|
+ (void)initWebviewWithBridge:(QSHWebView*)webview url:(NSURL*)url webDelegate:(QSHWebViewDelegate*)webDelegate isMain:(BOOL)isMain
|
|
{
|
|
// Create Bridge
|
|
WKWebViewJavascriptBridge* _WKBridge = [WKWebViewJavascriptBridge bridgeForWebView:webview];
|
|
webview.bridge = _WKBridge;
|
|
if (isMain){
|
|
webDelegate.mainBridge = _WKBridge;
|
|
}
|
|
|
|
[_WKBridge registerHandler:@"quark" handler:^(id data, WVJBResponseCallback responseCallback) {
|
|
if ([data isKindOfClass:[NSDictionary class]]) {
|
|
NSLog(@"Trigger method: %@ from JS", data[@"method"]);
|
|
NSString *method = data[@"method"];
|
|
if (![QSHWebViewDelegate isMethodExcludedFromWebScript:method]) return;
|
|
|
|
NSArray *args = @[];
|
|
if ([QSHWebViewDelegate isMethodReceiveWebView:method]){
|
|
args = [args arrayByAddingObject:webview];
|
|
} else if ([QSHWebViewDelegate isMethodResponseToJS:method]) {
|
|
args = [args arrayByAddingObject:responseCallback];
|
|
}
|
|
|
|
SEL methodSEL = NSSelectorFromString([data[@"method"] stringByAppendingString:@":"]);
|
|
[webDelegate performSelector:methodSEL withObject:[args arrayByAddingObjectsFromArray:data[@"args"]]];
|
|
}
|
|
}];
|
|
|
|
// Load Page
|
|
[webview loadRequest:[NSURLRequest requestWithURL:url]];
|
|
|
|
// NSURL *top = [NSURL URLWithString:[[url absoluteString] stringByDeletingLastPathComponent]];
|
|
// NSURL *newUrl = [NSURL URLWithString:[url absoluteString]];
|
|
// NSLog(@"toload: %@", newUrl);
|
|
// [webview loadFileURL:newUrl allowingReadAccessToURL:top];
|
|
}
|
|
|
|
#pragma mark WebScripting Protocol
|
|
|
|
+ (BOOL)isMethodReceiveWebView:(NSString *)method
|
|
{
|
|
return [@[
|
|
@"closeWindow",
|
|
@"setInterval",
|
|
@"clearInterval"
|
|
] isIncludeString:method];
|
|
}
|
|
|
|
+ (BOOL)isMethodResponseToJS:(NSString *)method
|
|
{
|
|
return [@[
|
|
@"getPref",
|
|
@"getPinPopup",
|
|
@"getShowDockIcon",
|
|
@"getLaunchAtLogin",
|
|
@"setPref"
|
|
] isIncludeString:method];
|
|
}
|
|
|
|
+ (BOOL)isMethodExcludedFromWebScript:(NSString *)method
|
|
{
|
|
return [@[
|
|
@"openPopup",
|
|
@"closePopup",
|
|
@"togglePopup",
|
|
@"resizePopup",
|
|
@"quit",
|
|
@"openURL",
|
|
@"playSound",
|
|
@"stopSound",
|
|
@"changeIcon",
|
|
@"changeHighlightedIcon",
|
|
@"changeClickAction",
|
|
@"changeSecondaryClickAction",
|
|
@"changeLabel",
|
|
@"resetMenubarIcon",
|
|
@"setLaunchAtLogin",
|
|
@"getLaunchAtLogin",
|
|
@"setShowDockIcon",
|
|
@"getShowDockIcon",
|
|
@"notify",
|
|
@"removeAllScheduledNotifications",
|
|
@"removeAllDeliveredNotifications",
|
|
@"addKeyboardShortcut",
|
|
@"clearKeyboardShortcut",
|
|
@"setupPreferences",
|
|
@"openPreferences",
|
|
@"closePreferences",
|
|
@"newWindow",
|
|
@"closeWindow",
|
|
@"closeWindowById",
|
|
@"getPinPopup",
|
|
@"setPinPopup",
|
|
@"getPref",
|
|
@"setPref",
|
|
@"checkUpdate",
|
|
@"checkUpdateInBackground",
|
|
@"emitMessage",
|
|
@"setMainMenu",
|
|
@"setInterval",
|
|
@"clearInterval",
|
|
@"setMainMenu",
|
|
@"showMenu",
|
|
] isIncludeString:method];
|
|
}
|
|
|
|
+ (BOOL)isKeyExcludedFromWebScript:(const char *)name
|
|
{
|
|
if (strncmp(name, "appVersion", 10) == 0 ||
|
|
strncmp(name, "appBundleVersion", 16) == 0 ||
|
|
strncmp(name, "platform", 8) == 0 ||
|
|
strncmp(name, "debug", 5) == 0) {
|
|
return NO;
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark - Methods for JavaScript
|
|
|
|
- (void)openPopup:(NSArray *)args
|
|
{
|
|
[self.appDelegate showWindow];
|
|
}
|
|
|
|
- (void)closePopup:(NSArray *)args
|
|
{
|
|
[self.appDelegate hideWindow];
|
|
}
|
|
|
|
- (void)togglePopup:(NSArray *)args
|
|
{
|
|
[self.appDelegate toggleWindow];
|
|
}
|
|
|
|
- (void)resizePopup:(NSArray *)args
|
|
{
|
|
NSDictionary *options = args[0];
|
|
CGFloat width = [options[@"width"] doubleValue];
|
|
CGFloat height = [options[@"height"] doubleValue];
|
|
|
|
if (options[@"width"] && options[@"height"]) {
|
|
[self.appDelegate resizeWindow:CGSizeMake(width, height)];
|
|
}
|
|
}
|
|
|
|
- (void)quit:(NSArray *)args
|
|
{
|
|
[NSApp terminate:nil];
|
|
}
|
|
|
|
- (void)openURL:(NSArray *)args
|
|
{
|
|
NSString *url = args[0];
|
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]];
|
|
}
|
|
|
|
- (void)changeIcon:(NSArray *)args
|
|
{
|
|
NSString *base64 = args[0];
|
|
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:base64]];
|
|
NSImage *icon = [[NSImage alloc] initWithData:data];
|
|
icon.size = NSMakeSize(20, 20);
|
|
|
|
[icon setTemplate:YES];
|
|
self.statusItem.button.image = icon;
|
|
}
|
|
|
|
- (void)changeHighlightedIcon:(NSArray *)args
|
|
{
|
|
NSString *base64 = args[0];
|
|
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:base64]];
|
|
NSImage *icon = [[NSImage alloc] initWithData:data];
|
|
self.statusItemView.highlightedIcon = icon;
|
|
}
|
|
|
|
- (void)changeClickAction:(NSArray *)args
|
|
{
|
|
self.appDelegate.clickCallback = ^{
|
|
};
|
|
}
|
|
|
|
- (void)changeSecondaryClickAction:(NSArray *)args
|
|
{
|
|
self.appDelegate.secondaryClickCallback = ^{
|
|
};
|
|
}
|
|
|
|
- (void)resetMenubarIcon:(NSArray *)args
|
|
{
|
|
if (IS_PRIOR_TO_10_9) {
|
|
self.statusItemView.icon = [NSImage imageNamed:@"StatusIcon"];
|
|
self.statusItemView.highlightedIcon = [NSImage imageNamed:@"StatusIconWhite"];
|
|
}
|
|
else {
|
|
NSImage *icon = [NSImage imageNamed:@"StatusIcon"];
|
|
[icon setTemplate:YES];
|
|
self.statusItem.button.image = icon;
|
|
}
|
|
}
|
|
|
|
- (void)changeLabel:(NSArray *)args
|
|
{
|
|
NSString *label = args[0];
|
|
NSDictionary *barTextAttributes;
|
|
self.statusItem.title = label;
|
|
if (!IS_PRIOR_TO_10_10) {
|
|
self.statusItem.button.font = MENUBAR_FONT_10_11;
|
|
}
|
|
barTextAttributes = @{NSFontAttributeName: self.statusItem.button.font};
|
|
|
|
// 20 is image width, 10 is extra margin
|
|
self.statusItem.length = 20 + [label sizeWithAttributes:barTextAttributes].width + 10;
|
|
}
|
|
|
|
- (void)setShowDockIcon:(NSArray *)args
|
|
{
|
|
bool showDockIcon = [args[0] boolValue];
|
|
[self.appDelegate showDockIcon:showDockIcon];
|
|
}
|
|
|
|
- (void)getShowDockIcon:(NSArray *)args
|
|
{
|
|
WVJBResponseCallback responseCallback = args[0];
|
|
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
|
NSString *value = [userPreferences stringForKey:@"showDockIcon"];
|
|
responseCallback(value);
|
|
}
|
|
|
|
- (void)getPref:(NSArray *)args
|
|
{
|
|
WVJBResponseCallback responseCallback = args[0];
|
|
NSString *key = args[1];
|
|
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
|
NSString *value = [userPreferences stringForKey:key];
|
|
responseCallback(value);
|
|
}
|
|
|
|
- (void)setPref:(NSArray *)args
|
|
{
|
|
WVJBResponseCallback responseCallback = args[0];
|
|
NSString *key = args[1];
|
|
NSString *value = args[2];
|
|
if (!([value length] > 0)) {
|
|
value = @"";
|
|
}
|
|
|
|
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
|
[userPreferences setObject:value forKey:key];
|
|
[userPreferences synchronize];
|
|
responseCallback(value);
|
|
}
|
|
|
|
- (void)setLaunchAtLogin:(NSArray *)args
|
|
{
|
|
BOOL launchAtLogin;
|
|
if ([args[0] isEqual: @"true"]){
|
|
launchAtLogin = true;
|
|
}else{
|
|
launchAtLogin = false;
|
|
}
|
|
|
|
StartAtLoginController *loginController = [[StartAtLoginController alloc] initWithIdentifier:@"com.hackplan.quark-shell-helper"];
|
|
loginController.startAtLogin = launchAtLogin;
|
|
}
|
|
|
|
- (void)getLaunchAtLogin:(NSArray *)args
|
|
{
|
|
WVJBResponseCallback responseCallback = args[0];
|
|
StartAtLoginController *loginController = [[StartAtLoginController alloc] initWithIdentifier:@"com.hackplan.quark-shell-helper"];
|
|
NSString *value = @([loginController startAtLogin]).stringValue;
|
|
responseCallback(value);
|
|
}
|
|
|
|
- (void)notify:(NSArray *)args
|
|
{
|
|
NSDictionary *message = args[0];
|
|
|
|
NSUserNotification *notification = [[NSUserNotification alloc] init];
|
|
notification.title = message[@"title"];
|
|
notification.informativeText = message[@"content"];
|
|
notification.deliveryDate = [NSDate date];
|
|
notification.soundName = NSUserNotificationDefaultSoundName;
|
|
notification.userInfo = @{@"popupOnClick": message[@"popupOnClick"]};
|
|
|
|
if (message[@"time"]) {
|
|
static ISO8601DateFormatter *formatter;
|
|
if (!formatter) {
|
|
formatter = [[ISO8601DateFormatter alloc] init];
|
|
}
|
|
notification.deliveryDate = [formatter dateFromString:message[@"time"]];
|
|
}
|
|
|
|
NSUserNotificationCenter *notificationCenter = [NSUserNotificationCenter defaultUserNotificationCenter];
|
|
notificationCenter.delegate = self;
|
|
[notificationCenter scheduleNotification:notification];
|
|
}
|
|
|
|
- (void)removeAllScheduledNotifications:(NSArray *)args
|
|
{
|
|
NSUserNotificationCenter *notificationCenter = [NSUserNotificationCenter defaultUserNotificationCenter];
|
|
notificationCenter.scheduledNotifications = @[];
|
|
}
|
|
|
|
- (void)removeAllDeliveredNotifications:(NSArray *)args
|
|
{
|
|
NSUserNotificationCenter *notificationCenter = [NSUserNotificationCenter defaultUserNotificationCenter];
|
|
[notificationCenter removeAllDeliveredNotifications];
|
|
}
|
|
|
|
- (void)addKeyboardShortcut:(NSArray *)args
|
|
{
|
|
NSDictionary* shortcutObj = args[0];
|
|
NSUInteger keycode = [[shortcutObj valueForKey:@"keycode"] integerValue];
|
|
NSUInteger flags = [[shortcutObj valueForKey:@"modifierFlags"] integerValue];
|
|
|
|
if (keycode == 0 && flags == 0) {
|
|
// the shortcut recorder returns 0 0 for no shortcut
|
|
// however, 0 0 is a single 'a', in this case, shouldn't be fired
|
|
return;
|
|
}
|
|
|
|
NSString *callbackId = [shortcutObj valueForKey:@"id"];
|
|
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
|
MASShortcut *shortcut = [MASShortcut shortcutWithKeyCode:keycode modifierFlags:flags];
|
|
// FIXME: value my not be the shortcut object
|
|
[userPreferences setObject:shortcut forKey:[@"values.shortcut_" stringByAppendingString:callbackId]];
|
|
[userPreferences synchronize];
|
|
}
|
|
|
|
- (void)clearKeyboardShortcut:(NSArray *)args
|
|
{
|
|
[[MASShortcutMonitor sharedMonitor] unregisterAllShortcuts];
|
|
}
|
|
|
|
- (void)setupPreferences:(NSArray *)args
|
|
{
|
|
NSArray *preferencesArray = args[0];
|
|
NSMutableArray *viewControllers = [NSMutableArray array];
|
|
|
|
for (NSDictionary *preferences in preferencesArray) {
|
|
NSInteger height = preferences[@"height"] ? [preferences[@"height"] integerValue]: kPreferencesDefaultHeight;
|
|
QSHPreferencesViewController *vc = [[QSHPreferencesViewController alloc]
|
|
initWithIdentifier:preferences[@"identifier"]
|
|
url:preferences[@"url"]
|
|
toolbarImage:[NSImage imageNamed:preferences[@"icon"]]
|
|
toolbarLabel:preferences[@"label"]
|
|
height:height
|
|
delegate:self];
|
|
|
|
for (NSDictionary *component in preferences[@"nativeComponents"]) {
|
|
[vc addNativeComponent:component];
|
|
}
|
|
|
|
[viewControllers addObject:vc];
|
|
}
|
|
self.prefWindows = viewControllers;
|
|
|
|
NSString *title = NSLocalizedString(@"Preferences", @"Common title for Preferences window");
|
|
self.preferencesWindowController = [[MASPreferencesWindowController alloc] initWithViewControllers:viewControllers title:title];
|
|
[self.preferencesWindowController selectControllerAtIndex:0];
|
|
}
|
|
|
|
- (void)openPreferences:(NSArray *)args
|
|
{
|
|
[self.preferencesWindowController showWindow:nil];
|
|
}
|
|
|
|
- (void)closePreferences:(NSArray *)args
|
|
{
|
|
[self.preferencesWindowController close];
|
|
}
|
|
|
|
- (void)removeWindowFromWindows:(QSHWebViewWindowController *)windowController
|
|
{
|
|
[self.webView.bridge callHandler:@"onQuarkWindowClose" data:windowController.windowId];
|
|
[self.windows removeObject:windowController];
|
|
}
|
|
|
|
- (void)newWindow:(NSArray *)args
|
|
{
|
|
NSDictionary *options = args[0];
|
|
NSString *urlString = options[@"url"];
|
|
NSString *windowId = options[@"id"];
|
|
CGFloat width = [options[@"width"] doubleValue];
|
|
CGFloat height = [options[@"height"] doubleValue];
|
|
bool bringWindowToFrontInsteadOfCloseIt = options[@"toFront"];
|
|
|
|
QSHWebViewWindowController *webViewWindowController;
|
|
webViewWindowController = [[QSHWebViewWindowController alloc] initWithURLString:urlString width:width height:height webDelegate:self windowId:windowId];
|
|
|
|
// if window with same key exist, close it before open a new one
|
|
if (windowId){
|
|
|
|
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"windowId == %@", windowId];
|
|
NSArray *existedWindows = [self.windows filteredArrayUsingPredicate:predicate];
|
|
|
|
if ([existedWindows count] > 0){
|
|
for (QSHWebViewWindowController *window in existedWindows) {
|
|
if (bringWindowToFrontInsteadOfCloseIt){
|
|
return [window.window makeKeyAndOrderFront:nil];
|
|
} else{
|
|
[window close];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[self.windows addObject:webViewWindowController];
|
|
|
|
if (options[@"x"] && options[@"y"]) {
|
|
CGFloat screenWidth = [[NSScreen mainScreen] frame].size.width;
|
|
CGFloat screenHeight = [[NSScreen mainScreen] frame].size.height;
|
|
|
|
CGFloat x = [options[@"x"] doubleValue];
|
|
if ([options[@"x"] isEqual:@"center"]) {
|
|
x = (screenWidth - width) / 2;
|
|
}
|
|
CGFloat yFlipped = screenHeight - [options[@"y"] doubleValue] - height;
|
|
if ([options[@"y"] isEqual:@"center"]) {
|
|
yFlipped = (screenHeight - height) / 2;
|
|
}
|
|
|
|
[webViewWindowController.window setFrameOrigin:NSMakePoint(x, yFlipped)];
|
|
}
|
|
|
|
if (options[@"minWidth"] && options[@"minHeight"]){
|
|
NSSize minSize = NSMakeSize([options[@"minWidth"] doubleValue], [options[@"minHeight"] doubleValue]);
|
|
[webViewWindowController.window setMinSize:minSize];
|
|
}
|
|
|
|
|
|
if (options[@"resizable"] && [options[@"resizable"] boolValue] == NO) {
|
|
[webViewWindowController.window setStyleMask:[webViewWindowController.window styleMask] & ~NSResizableWindowMask];
|
|
}
|
|
|
|
if (options[@"transparentTitle"] && [options[@"transparentTitle"] boolValue] == YES) {
|
|
webViewWindowController.window.styleMask = webViewWindowController.window.styleMask | NSWindowStyleMaskFullSizeContentView;
|
|
webViewWindowController.window.titleVisibility = NSWindowTitleHidden;
|
|
webViewWindowController.window.titlebarAppearsTransparent = YES;
|
|
}
|
|
|
|
if (options[@"border"] && [options[@"border"] boolValue] == NO) {
|
|
webViewWindowController.window.styleMask = NSBorderlessWindowMask;
|
|
}
|
|
|
|
if (options[@"shadow"] && [options[@"shadow"] boolValue] == NO) {
|
|
webViewWindowController.window.hasShadow = NO;
|
|
}
|
|
|
|
if ([options[@"alwaysOnTop"] boolValue]) {
|
|
webViewWindowController.window.level = NSModalPanelWindowLevel;
|
|
}
|
|
|
|
if (options[@"alpha"]) {
|
|
webViewWindowController.window.alphaValue = [options[@"alpha"] doubleValue];
|
|
}
|
|
|
|
[webViewWindowController showWindow:nil];
|
|
|
|
if ([options[@"titleBarStyle"] isEqual: @"hidden-inset"]){
|
|
[webViewWindowController.window setTitleVisibility:NSWindowTitleHidden];
|
|
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"];
|
|
toolbar.showsBaselineSeparator = NO;
|
|
[webViewWindowController.window setToolbar:toolbar];
|
|
}
|
|
|
|
}
|
|
|
|
- (void)closeWindowById:(NSArray *)args
|
|
{
|
|
NSDictionary *options = args[0];
|
|
NSString *windowId = options[@"id"];
|
|
|
|
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"windowId == %@", windowId];
|
|
NSArray *existedWindows = [self.windows filteredArrayUsingPredicate:predicate];
|
|
|
|
if ([existedWindows count] > 0){
|
|
for (QSHWebViewWindowController *window in existedWindows) {
|
|
[window close];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)closeWindow:(NSArray *)args
|
|
{
|
|
QSHWebView *webview = args[0];
|
|
[webview.parentWindow close];
|
|
}
|
|
|
|
- (void)playSound:(NSArray *)args
|
|
{
|
|
NSDictionary *options = args[0];
|
|
NSString *urlString = options[@"path"];
|
|
NSInteger loop = [options[@"loop"] integerValue];
|
|
|
|
NSURL *soundUrl = [NSURL URLWithString:urlString relativeToURL:[QSHWebViewDelegate getRootURL]];
|
|
|
|
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:nil];
|
|
[_audioPlayer setNumberOfLoops:loop];
|
|
[_audioPlayer prepareToPlay];
|
|
[_audioPlayer play];
|
|
}
|
|
|
|
- (void)stopSound:(NSArray *)args
|
|
{
|
|
[_audioPlayer stop];
|
|
}
|
|
|
|
- (void)setPinPopup:(NSArray *)args
|
|
{
|
|
bool pinned = [args[0] boolValue];
|
|
[[NSUserDefaults standardUserDefaults] setBool:pinned forKey:@"pinned"];
|
|
self.appDelegate.pinned = pinned;
|
|
}
|
|
|
|
- (void)getPinPopup:(NSArray *)args
|
|
{
|
|
WVJBResponseCallback responseCallback = args[0];
|
|
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
|
|
NSString *value = [userPreferences stringForKey:@"pinned"];
|
|
responseCallback(value);
|
|
}
|
|
|
|
- (void)checkUpdate:(NSArray *)args
|
|
{
|
|
NSString *url = args[0];
|
|
SUUpdater *updater = [[SUUpdater alloc] init];
|
|
updater.feedURL = [NSURL URLWithString:url];
|
|
[updater checkForUpdates:nil];
|
|
}
|
|
|
|
- (void)checkUpdateInBackground:(NSArray *)args
|
|
{
|
|
NSString *url = args[0];
|
|
SUUpdater *updater = [[SUUpdater alloc] init];
|
|
updater.feedURL = [NSURL URLWithString:url];
|
|
[updater checkForUpdatesInBackground];
|
|
}
|
|
|
|
- (void)emitMessage:(NSArray *)arg
|
|
{
|
|
NSMutableArray *bridges = [[NSMutableArray alloc] init];
|
|
for (QSHWebViewWindowController *window in self.windows) {
|
|
[bridges addObject:window.webView.bridge];
|
|
}
|
|
for (QSHPreferencesViewController *pvc in self.prefWindows) {
|
|
if (pvc.webView.bridge != nil) {
|
|
[bridges addObject:pvc.webView.bridge];
|
|
}
|
|
}
|
|
[bridges addObject:self.mainBridge];
|
|
|
|
for (WKWebViewJavascriptBridge *b in bridges) {
|
|
[b callHandler:@"onQuarkMessage" data:arg[0]];
|
|
}
|
|
}
|
|
|
|
- (void)setMainMenu:(NSArray *)args
|
|
{
|
|
NSDictionary *options = args[0];
|
|
NSMenu *menu = [[NSApplication sharedApplication] mainMenu];
|
|
menu.autoenablesItems = NO;
|
|
for (NSDictionary *item in options[@"items"]) {
|
|
if ([item[@"type"] isEqualToString:@"separator"]) {
|
|
[menu addItem:[NSMenuItem separatorItem]];
|
|
}
|
|
else {
|
|
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:item[@"label"] action:@selector(menuItemClicked:) keyEquivalent:@""];
|
|
menuItem.target = self;
|
|
menuItem.representedObject = item[@"message"];
|
|
[menuItem setEnabled:YES];
|
|
[menu addItem:menuItem];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)showMenu:(NSArray *)args
|
|
{
|
|
NSDictionary *options = args[0];
|
|
NSMenu *menu = [[NSMenu alloc] init];
|
|
menu.autoenablesItems = NO;
|
|
for (NSDictionary *item in options[@"items"]) {
|
|
if ([item[@"type"] isEqualToString:@"separator"]) {
|
|
[menu addItem:[NSMenuItem separatorItem]];
|
|
}
|
|
else {
|
|
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:item[@"label"] action:@selector(menuItemClicked:) keyEquivalent:@""];
|
|
menuItem.target = self;
|
|
menuItem.representedObject = item[@"message"];
|
|
[menuItem setEnabled:YES];
|
|
[menu addItem:menuItem];
|
|
}
|
|
}
|
|
|
|
CGFloat x = [options[@"x"] doubleValue];
|
|
CGFloat yFlipped = self.webView.frame.size.height - [options[@"y"] doubleValue];
|
|
[menu popUpMenuPositioningItem:nil atLocation:NSMakePoint(x, yFlipped) inView:self.webView];
|
|
}
|
|
|
|
- (void)setInterval:(NSArray *)args
|
|
{
|
|
QSHWebView *webview = args[0];
|
|
NSNumber *timerId = args[1];
|
|
NSNumber *interval = args[2];
|
|
bool isRepeat = args.count > 2 ? [args[2] boolValue] : true;
|
|
[webview setInterval:timerId interval:interval isRepeat:isRepeat];
|
|
}
|
|
|
|
- (void)clearInterval:(NSArray *)args
|
|
{
|
|
QSHWebView *webview = args[0];
|
|
NSNumber *timerId = args[1];
|
|
[webview clearInterval:timerId];
|
|
}
|
|
|
|
#pragma mark - Private methods
|
|
|
|
- (void)menuItemClicked:(NSMenuItem *)sender
|
|
{
|
|
NSArray *args = [NSArray arrayWithObject:sender.representedObject];
|
|
[self emitMessage:args];
|
|
}
|
|
|
|
#pragma mark - Delegate methods
|
|
|
|
- (void)webView:(WKWebView *)webView addMessageToConsole:(NSDictionary *)message
|
|
{
|
|
if (![message isKindOfClass:[NSDictionary class]]) {
|
|
return;
|
|
}
|
|
|
|
NSLog(@"JavaScript console: %@:%@: %@",
|
|
[message[@"sourceURL"] lastPathComponent],
|
|
message[@"lineNumber"],
|
|
message[@"message"]);
|
|
}
|
|
|
|
- (void)webView:(QSHWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
|
|
{
|
|
NSAlert *alert = [[NSAlert alloc] init];
|
|
[alert addButtonWithTitle:@"OK"];
|
|
alert.messageText = message;
|
|
alert.alertStyle = NSWarningAlertStyle;
|
|
|
|
[alert runModal];
|
|
completionHandler();
|
|
}
|
|
|
|
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
|
|
|
|
{
|
|
NSAlert *alert = [[NSAlert alloc] init];
|
|
[alert addButtonWithTitle:@"Yes"];
|
|
[alert addButtonWithTitle:@"No"];
|
|
alert.messageText = message;
|
|
alert.alertStyle = NSWarningAlertStyle;
|
|
|
|
if ([alert runModal] == NSAlertFirstButtonReturn) {
|
|
completionHandler(YES);
|
|
}
|
|
else {
|
|
completionHandler(NO);
|
|
}
|
|
}
|
|
|
|
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)message defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler
|
|
{
|
|
NSArray *components = [message componentsSeparatedByString: @"::"];
|
|
message = (NSString*) [components objectAtIndex:0];
|
|
NSString *okText = nil;
|
|
NSString *cancelText = nil;
|
|
if ([components count] > 1) {
|
|
okText = (NSString*) [components objectAtIndex:1];
|
|
@try{
|
|
cancelText = (NSString*) [components objectAtIndex:2];
|
|
} @catch (NSException * e) {
|
|
NSLog(@"Exception: %@", e);
|
|
}
|
|
}
|
|
if (okText.length < 1) {
|
|
okText = NSLocalizedString(@"OK", @"");
|
|
}
|
|
|
|
NSAlert *alert = [[NSAlert alloc] init];
|
|
|
|
[alert addButtonWithTitle: okText];
|
|
[alert addButtonWithTitle: cancelText];
|
|
[alert setMessageText:message];
|
|
NSTextField* input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)];
|
|
[input setStringValue:defaultText];
|
|
[alert setAccessoryView:input];
|
|
|
|
NSInteger button = [alert runModal];
|
|
if (button == NSAlertFirstButtonReturn) {
|
|
[input validateEditing];
|
|
return completionHandler([input stringValue]);
|
|
}
|
|
|
|
completionHandler(nil);
|
|
|
|
}
|
|
|
|
// Enable <input type="file">
|
|
- (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id < WebOpenPanelResultListener >)resultListener
|
|
{
|
|
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
|
openPanel.canChooseFiles = YES;
|
|
openPanel.canChooseDirectories = NO;
|
|
|
|
[openPanel beginWithCompletionHandler:^(NSInteger result) {
|
|
if (result == NSFileHandlingPanelOKButton) {
|
|
NSURL *fileURL = openPanel.URL;
|
|
[resultListener chooseFilename:fileURL.relativePath];
|
|
}
|
|
}];
|
|
}
|
|
|
|
#pragma mark WebPolicyDelegate
|
|
|
|
- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
|
|
{
|
|
NSString *scheme = request.URL.scheme;
|
|
if ([scheme isEqualToString:@"file"]) {
|
|
[listener use];
|
|
}
|
|
else {
|
|
[listener ignore];
|
|
[[NSWorkspace sharedWorkspace] openURL:request.URL];
|
|
}
|
|
}
|
|
|
|
#pragma mark - WebUIDelegate
|
|
|
|
- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems
|
|
{
|
|
if (debug) {
|
|
return defaultMenuItems;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
#pragma mark - NSUserNotificationCenterDelegate
|
|
|
|
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
|
|
{
|
|
if (notification.userInfo[@"popupOnClick"]) {
|
|
[self.appDelegate showWindow];
|
|
}
|
|
[[NSUserNotificationCenter defaultUserNotificationCenter] removeDeliveredNotification:notification];
|
|
}
|
|
|
|
#pragma mark - WKNavigationDelegate
|
|
|
|
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
|
|
{
|
|
QSHWebView *qshWebView = (QSHWebView *)webView;
|
|
[qshWebView clearAllIntervalTimer];
|
|
}
|
|
|
|
@end
|