OSDN Git Service

処理を簡素化した
[kcd/KCD.git] / KCD / GameViewController.swift
1 //
2 //  GameViewController.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2016/12/31.
6 //  Copyright © 2016年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10 import WebKit
11 import JavaScriptCore
12
13 fileprivate extension Selector {
14     
15     static let reloadContent = #selector(GameViewController.reloadContent(_:))
16     static let deleteCacheAndReload = #selector(GameViewController.deleteCacheAndReload(_:))
17     static let screenShot = #selector(GameViewController.screenShot(_:))
18 }
19
20 final class GameViewController: NSViewController {
21     
22     private static let gamePageURL = "http://www.dmm.com/netgame/social/-/gadgets/=/app_id=854854/"
23     private static let loginPageURLPrefix = "https://www.dmm.com/my/-/login/=/"
24     
25     @IBOutlet var webView: WebView!
26     
27     override var nibName: String! {
28         
29         return "GameViewController"
30     }
31     
32     fileprivate var flashTopLeft = NSPoint(x: 2600, y: 1445)
33     private var clipView: NSClipView {
34         
35         return view as! NSClipView  // swiftlint:disable:this force_cast
36     }
37     
38     override func viewDidLoad() {
39         
40         super.viewDidLoad()
41         
42         clipView.documentView = webView
43         
44         adjustFlash()
45         
46         webView.mainFrame.frameView.allowsScrolling = false
47         
48         webView.applicationNameForUserAgent = AppDelegate.shared.appNameForUserAgent
49         webView.mainFrameURL = GameViewController.gamePageURL
50     }
51     
52     func adjustFlash() {
53         
54         webView.superview?.scroll(flashTopLeft)
55     }
56     
57     @IBAction func reloadContent(_ sender: AnyObject?) {
58         
59         guard let _ = webView.mainFrameURL
60             else {
61                 webView.mainFrameURL = GameViewController.gamePageURL
62                 return
63         }
64         
65         // ゲームページでない場合はゲームページを表示する
66         if webView.mainFrameURL != GameViewController.gamePageURL {
67             
68             webView.mainFrameURL = GameViewController.gamePageURL
69             
70             return
71         }
72         if webView.mainFrameURL.hasPrefix(GameViewController.loginPageURLPrefix) {
73             
74             webView.reload(sender)
75             
76             return
77         }
78         
79         adjustFlash()
80         
81         let prevDate = UserDefaults.standard.prevReloadDate
82         if let prevDate = prevDate {
83             
84             let now = Date(timeIntervalSinceNow: 0.0)
85             if now.timeIntervalSince(prevDate) < 1 * 60 {
86                 
87                 let untilDate = prevDate.addingTimeInterval(1 * 60)
88                 let date = DateFormatter.localizedString(from: untilDate, dateStyle: .none, timeStyle: .medium)
89                 let alert = NSAlert()
90                 alert.messageText = NSLocalizedString("Reload interval is too short?", comment: "")
91                 let format = NSLocalizedString("Reload interval is too short.\nWait until %@.", comment: "")
92                 alert.informativeText = String(format: format, date)
93                 alert.runModal()
94                 
95                 return
96             }
97         }
98         
99         webView.reload(sender)
100         
101         UserDefaults.standard.prevReloadDate = Date(timeIntervalSinceNow: 0.0)
102     }
103     
104     @IBAction func deleteCacheAndReload(_ sender: AnyObject?) {
105         
106         let panel = ProgressPanel()
107         
108         guard let window = view.window,
109             let panelWindow = panel.window
110             else { return }
111         
112         panel.title = ""
113         panel.message = NSLocalizedString("Deleting caches...", comment: "Deleting caches...")
114         panel.animate = true
115         
116         window.beginSheet(panelWindow) { _ in NSSound(named: "Submarine")?.play() }
117         
118         AppDelegate.shared.clearCache()
119         
120         window.endSheet(panelWindow)
121     }
122     
123     @IBAction func screenShot(_ sender: AnyObject?) {
124         
125         let frame = webView.visibleRect
126         let screenshotBorder = UserDefaults.standard.screenShotBorderWidth
127         let f = frame.insetBy(dx: -screenshotBorder, dy: -screenshotBorder)
128         
129         guard let rep = webView.bitmapImageRepForCachingDisplay(in: f) else { return }
130         
131         webView.cacheDisplay(in: frame, to: rep)
132         AppDelegate.shared.registerScreenshot(rep, fromOnScreen: .zero)
133     }
134     
135     override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
136         
137         if menuItem.action == .reloadContent {
138             
139             guard let _ = webView.mainFrame,
140                 let frameURL = webView.mainFrameURL
141                 else { return true }
142             
143             switch frameURL {
144             case GameViewController.gamePageURL:
145                 menuItem.title = NSLocalizedString("Reload", comment: "Reload menu, reload")
146                 
147             case let s where s.hasPrefix(GameViewController.loginPageURLPrefix):
148                 menuItem.title = NSLocalizedString("Reload", comment: "Reload menu, reload")
149                 
150             default:
151                 menuItem.title = NSLocalizedString("Back To Game", comment: "Reload menu, back to game")
152             }
153             
154             return true
155         }
156         
157         if menuItem.action == .deleteCacheAndReload {
158             
159             return true
160         }
161         
162         if menuItem.action == .screenShot {
163             
164             return true
165         }
166         
167         return false
168     }
169 }
170
171 extension GameViewController: WebFrameLoadDelegate, WebUIDelegate {
172     
173     private static let excludeMenuItemTag = [
174         WebMenuItemTagOpenLinkInNewWindow,
175         WebMenuItemTagDownloadLinkToDisk,
176         WebMenuItemTagOpenImageInNewWindow,
177         WebMenuItemTagOpenFrameInNewWindow,
178         WebMenuItemTagGoBack,
179         WebMenuItemTagGoForward,
180         WebMenuItemTagStop,
181         WebMenuItemTagReload
182     ]
183     
184     func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {
185         
186         guard let path = frame.dataSource?.initialRequest.url?.path
187             else { return }
188         
189         let handler: (JSContext?, JSValue?) -> Void = { (_, exception) in
190             
191             if let exception = exception {
192                 
193                 print("Caught exception in evaluteScript -> \(exception)")
194                 
195             } else {
196                 
197                 print("Caught exception in evaluteScript")
198                 
199             }
200         }
201         
202         if path.hasSuffix("gadgets/ifr") {
203             
204             guard let context = frame.javaScriptContext
205                 else { return }
206             
207             context.exceptionHandler = handler
208             context.evaluateScript(
209                 ["var emb = document.getElementById('flashWrap');",
210                  "var rect = emb.getBoundingClientRect();",
211                  "var atop = rect.top;",
212                  "var aleft = rect.left;"]
213                     .reduce("", +)
214             )
215             let top = context.objectForKeyedSubscript("atop").toDouble()
216             let left = context.objectForKeyedSubscript("aleft").toDouble()
217             flashTopLeft = NSPoint(x: CGFloat(left), y: webView.frame.size.height - CGFloat(top) - 480)
218         }
219         
220         if path.hasSuffix("app_id=854854") {
221             
222             guard let context = frame.javaScriptContext
223                 else { return }
224             
225             context.exceptionHandler = handler
226             context.evaluateScript(
227                 ["var iframe = document.getElementById('game_frame');",
228                  "var validIframe = 0;",
229                  "if(iframe) {",
230                  "    validIframe = 1;",
231                  "    var rect = iframe.getBoundingClientRect();",
232                  "    var atop = rect.top;",
233                  "    var aleft = rect.left;",
234                  "}"]
235                     .reduce("", +)
236             )
237             let validIframe = context.objectForKeyedSubscript("validIframe").toInt32()
238             
239             guard validIframe != 0
240                 else { return }
241             
242             let top = context.objectForKeyedSubscript("atop").toDouble()
243             let left = context.objectForKeyedSubscript("aleft").toDouble()
244             flashTopLeft = NSPoint(x: flashTopLeft.x + CGFloat(left), y: flashTopLeft.y - CGFloat(top))
245             
246             adjustFlash()
247         }
248     }
249     
250     func webView(_ sender: WebView!, contextMenuItemsForElement element: [AnyHashable: Any]!, defaultMenuItems: [Any]!) -> [Any]! {
251         
252         guard let menuItems = defaultMenuItems as? [NSMenuItem]
253             else { return [] }
254         
255         return menuItems.filter { !GameViewController.excludeMenuItemTag.contains($0.tag) }
256     }
257 }