2 // ExternalBrowserWindowController.swift
5 // Created by Hori,Masaki on 2016/12/23.
6 // Copyright © 2016年 Hori,Masaki. All rights reserved.
12 private extension Selector {
14 static let addBookmark = #selector(ExternalBrowserWindowController.addBookmark(_:))
15 static let showBookmark = #selector(ExternalBrowserWindowController.showBookmark(_:))
16 static let selectBookmark = #selector(ExternalBrowserWindowController.selectBookmark(_:))
17 static let reloadContent = #selector(ExternalBrowserWindowController.reloadContent(_:))
18 static let updateContentVisibleRect = #selector(ExternalBrowserWindowController.updateContentVisibleRect(_:))
21 final class ExternalBrowserWindowController: NSWindowController {
23 let managedObjectContext = BookmarkManager.shared().manageObjectContext
27 webView.removeObserver(self, forKeyPath: "canGoBack")
28 webView.removeObserver(self, forKeyPath: "canGoForward")
31 @IBOutlet var webView: WebView!
32 @IBOutlet var goSegment: NSSegmentedControl!
33 @IBOutlet var bookmarkListView: NSView!
35 override var windowNibName: NSNib.Name {
37 return .nibName(instanceOf: self)
40 @objc dynamic var canResize: Bool = true {
43 guard let window = window else { return }
45 if canResize == newValue { return }
47 var styleMask = window.styleMask
50 styleMask.insert(.resizable)
54 styleMask.remove(.resizable)
57 window.styleMask = styleMask
61 @objc dynamic var canScroll: Bool = true {
64 guard let webView = webView else { return }
66 if canScroll == newValue { return }
70 webView.mainFrame.frameView.allowsScrolling = true
74 webView.mainFrame.frameView.allowsScrolling = false
78 @objc dynamic var canMovePage: Bool = true
80 var urlString: String? {
82 return webView.mainFrameURL
85 var windowContentSize: NSSize {
88 guard let window = window else { return .zero }
90 return window.contentRect(forFrameRect: window.frame).size
93 guard let window = window else { return }
95 var contentRect: NSRect = .zero
96 contentRect.size = newValue
97 var newFrame = window.frameRect(forContentRect: contentRect)
98 let frame = window.frame
99 newFrame.origin.x = frame.minX
100 newFrame.origin.y = frame.maxY - newFrame.height
101 window.setFrame(newFrame, display: true)
105 var contentVisibleRect: NSRect {
107 get { return webView.mainFrame.frameView.documentView.visibleRect }
108 set { webView.mainFrame.frameView.documentView.scrollToVisible(newValue) }
111 private var bookmarkShowing: Bool = false
112 private var waitingBookmarkItem: Bookmark?
114 private lazy var bookmarkListViwController: BookmarkListViewController? = { [weak self] in
116 guard let `self` = self else { return nil }
118 let controller = BookmarkListViewController()
119 self.bookmarkListView = controller.view
120 controller.delegate = self
122 var frame = self.webView.frame
123 frame.size.width = 200
124 frame.origin.x = -200
125 self.bookmarkListView.frame = frame
126 self.webView.superview?.addSubview(self.bookmarkListView, positioned: .below, relativeTo: self.webView)
131 override func windowDidLoad() {
133 super.windowDidLoad()
135 webView.addObserver(self, forKeyPath: "canGoBack", context: nil)
136 webView.addObserver(self, forKeyPath: "canGoForward", context: nil)
137 webView.applicationNameForUserAgent = AppDelegate.shared.appNameForUserAgent
138 webView.frameLoadDelegate = self
141 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
143 if keyPath == "canGoBack" {
145 goSegment.setEnabled(webView.canGoBack, forSegment: 0)
150 if keyPath == "canGoForward" {
152 goSegment.setEnabled(webView.canGoForward, forSegment: 1)
157 super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
160 override func swipe(with event: NSEvent) {
162 if event.deltaX > 0 && showsBookmarkList() {
167 if event.deltaX < 0 && !showsBookmarkList() {
173 private func move(bookmark: Bookmark) {
177 AppDelegate.shared.createNewBrowser().move(bookmark: bookmark)
181 webView.mainFrameURL = bookmark.urlString
182 windowContentSize = bookmark.windowContentSize
183 canResize = bookmark.canResize
184 canScroll = bookmark.canScroll
185 waitingBookmarkItem = bookmark
188 private func showsBookmarkList() -> Bool {
190 return webView.frame.origin.x > 0
195 extension ExternalBrowserWindowController {
197 override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
199 guard let action = menuItem.action else { return false }
202 case Selector.addBookmark:
203 return webView.mainFrameURL != nil
205 case Selector.showBookmark:
206 if showsBookmarkList() {
208 menuItem.title = NSLocalizedString("Hide Bookmark", comment: "Menu item title, Hide Bookmark")
212 menuItem.title = NSLocalizedString("Show Bookmark", comment: "Menu item title, Show Bookmark")
216 case Selector.selectBookmark:
219 case Selector.reloadContent:
227 @IBAction func selectBookmark(_ sender: AnyObject?) {
229 guard let item = sender?.representedObject as? Bookmark else { return }
234 @IBAction func reloadContent(_ sender: AnyObject?) {
239 @IBAction func goHome(_ sender: AnyObject?) {
241 webView.mainFrameURL = "http://www.dmm.com/"
244 @IBAction func clickGoBackSegment(_ sender: AnyObject?) {
246 guard let cell = goSegment.cell as? NSSegmentedCell else { return }
248 let tag = cell.tag(forSegment: cell.selectedSegment)
254 webView.goForward(nil)
261 @IBAction func addBookmark(_ sender: AnyObject?) {
263 guard let window = window else { return }
264 guard let bookmark = BookmarkManager.shared().createNewBookmark() else { return }
266 bookmark.name = window.title
267 bookmark.urlString = webView.mainFrameURL
268 bookmark.windowContentSize = windowContentSize
269 bookmark.contentVisibleRect = contentVisibleRect
270 bookmark.canResize = canResize
271 bookmark.canScroll = canScroll
272 bookmark.scrollDelay = 0.5
275 @IBAction func showBookmark(_ sender: AnyObject?) {
277 guard let window = window else { return }
278 guard let _ = bookmarkListViwController else { return }
279 guard !bookmarkShowing else { return }
281 bookmarkShowing = true
283 var frame = bookmarkListView.frame
284 frame.size.height = webView.frame.size.height
285 bookmarkListView.frame = frame
287 var newFrame = webView.frame
289 if showsBookmarkList() {
291 frame.origin.x = -200
292 newFrame.origin.x = 0
293 newFrame.size.width = window.frame.size.width
298 newFrame.origin.x = 200
299 newFrame.size.width = window.frame.size.width - 200
302 let webAnime: [NSViewAnimation.Key: Any] = [
304 .endFrame: NSValue(rect: newFrame)
306 let bookmarkAnime: [NSViewAnimation.Key: Any] = [
307 .target: bookmarkListView,
308 .endFrame: NSValue(rect: frame)
310 let anime = NSViewAnimation(viewAnimations: [webAnime, bookmarkAnime])
311 anime.delegate = self
315 @IBAction func scrollLeft(_ sender: AnyObject?) {
317 var rect = contentVisibleRect
319 contentVisibleRect = rect
322 @IBAction func scrollRight(_ sender: AnyObject?) {
324 var rect = contentVisibleRect
326 contentVisibleRect = rect
329 @IBAction func scrollUp(_ sender: AnyObject?) {
331 var rect = contentVisibleRect
333 contentVisibleRect = rect
336 @IBAction func scrollDown(_ sender: AnyObject?) {
338 var rect = contentVisibleRect
340 contentVisibleRect = rect
343 @IBAction func increaseWidth(_ sender: AnyObject?) {
345 guard let window = window else { return }
347 var frame = window.frame
348 frame.size.width += 1
349 window.setFrame(frame, display: true)
352 @IBAction func decreaseWidth(_ sender: AnyObject?) {
354 guard let window = window else { return }
356 var frame = window.frame
357 frame.size.width -= 1
358 window.setFrame(frame, display: true)
361 @IBAction func increaseHeight(_ sender: AnyObject?) {
363 guard let window = window else { return }
365 var frame = window.frame
366 frame.size.height += 1
368 window.setFrame(frame, display: true)
371 @IBAction func decreaseHeight(_ sender: AnyObject?) {
373 guard let window = window else { return }
375 var frame = window.frame
376 frame.size.height -= 1
378 window.setFrame(frame, display: true)
382 extension ExternalBrowserWindowController: BookmarkListViewControllerDelegate {
384 func didSelectBookmark(_ bookmark: Bookmark) {
386 move(bookmark: bookmark)
390 extension ExternalBrowserWindowController: NSAnimationDelegate {
392 func animationDidEnd(_ animation: NSAnimation) {
394 bookmarkShowing = false
398 extension ExternalBrowserWindowController: WebFrameLoadDelegate, WebPolicyDelegate {
400 @objc func updateContentVisibleRect(_ timer: Timer) {
402 guard let item = timer.userInfo as? Bookmark else { return }
404 contentVisibleRect = item.contentVisibleRect
407 func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {
409 if let waitingBookmarkItem = waitingBookmarkItem {
411 Timer.scheduledTimer(timeInterval: waitingBookmarkItem.scrollDelay,
413 selector: .updateContentVisibleRect,
414 userInfo: waitingBookmarkItem,
417 waitingBookmarkItem = nil
420 func webView(_ webView: WebView!,
421 decidePolicyForNavigationAction actionInformation: [AnyHashable: Any]!,
422 request: URLRequest!,
424 decisionListener listener: WebPolicyDecisionListener!) {
426 if actionInformation?[WebActionNavigationTypeKey] as? WebNavigationType == .linkClicked {