I have a webView in my cocoa application (macosx not iphone), it displays some javascript to the user but I don't want the user to be able to select any of the text or right click and select the reload option.
Is there a simple way to disable all interaction with the webView?
I know on the iPhone its easy to disable user interaction but I have never needed to do this on the desktop before and can't find a solution.
Set both editing and UI delegations:
[view setUIDelegate:self];
[view setEditingDelegate:self];
Then add the methods above to disable text selection and context menu.
- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element
defaultMenuItems:(NSArray *)defaultMenuItems
{
// disable right-click context menu
return nil;
}
- (BOOL)webView:(WebView *)webView shouldChangeSelectedDOMRange:(DOMRange *)currentRange
toDOMRange:(DOMRange *)proposedRange
affinity:(NSSelectionAffinity)selectionAffinity
stillSelecting:(BOOL)flag
{
// disable text selection
return NO;
}
via the UI delegation it might be useful also to disable drag and drop operations, add
- (NSUInteger)webView:(WebView *)sender dragSourceActionMaskForPoint:(NSPoint)point
{
return WebDragSourceActionNone; // Disable any WebView content drag
}
- (NSUInteger)webView:(WebView *)sender dragDestinationActionMaskForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
{
return WebDragDestinationActionNone; // Disable any WebView content drop
}
Related
So I am presenting an NSViewController as a sheet of a window that has resize disabled.
The view controller that is presented as a sheet can still be resized.
How do I disable resizing of a NSViewController?
Swift 4:
override func viewDidAppear() {
// any additional code
view.window!.styleMask.remove(.resizable)
}
By the way you can do this without writing code, here is how:
Drag a Window Controller element to the Storyboard from the Object
Library.
Connect the Window Controller to the specific View Controller which you want to disable resize.
On the Window Controller's Attributes uncheck Resize option.
After some more trying I found out this did the trick in viewDidLoad:
self.preferredContentSize = NSMakeSize(self.view.frame.size.width, self.view.frame.size.height);
If you add these methods, the issue will be fixed.
- (void)updateViewConstraints NS_AVAILABLE_MAC(10_10) {
[super updateViewConstraints];
}
- (void)viewWillLayout NS_AVAILABLE_MAC(10_10) {
self.preferredContentSize = NSMakeSize(self.view.frame.size.width, self.view.frame.size.height);
}
My goal is simple and yet I cannot find a solution in spite of lots of searching.
Basically, when my app is in full-screen (kiosk) mode, I want the toolbar only to auto-hide, but I want the menu bar hidden.
Apparently this combination is not valid. I've tried:
- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions: (NSApplicationPresentationOptions)proposedOptions
{
return (NSApplicationPresentationFullScreen |
NSApplicationPresentationHideDock |
NSApplicationPresentationHideMenuBar |
NSApplicationPresentationAutoHideToolbar);
}
I get the following exception:
"... fullscreen presentation options must include NSApplicationPresentationAutoHideMenuBar if NSApplicationPresentationAutoHideToolbar is included"
Thing is, I don't want the menu bar displayed at all!
So, I'm presuming this is not possible using the standard presentation options. Any ideas how I might approach implementing this behaviour manually?
I'm thinking along the lines of: detect the mouse position and only show/hide the toolbar when the mouse is at/near the top of the screen.
I'm very new to Cocoa so not sure where I would start to achieve this. Any help much appreciated!
Many thanks,
John
I've got It to work, but only by using private APIs.
First I had to find out how to prevent the menubar from appearing. I discovered the functions _HIMenuBarPositionLock and _HIMenuBarPositionUnlock, from Carbon (link the app with Carbon.framework).
Then I had to create a custom subclass of NSToolbar, at awakeFromNib I register notification observers to lock and unlock the menubar when the window enters and exits fullscreen, respectively:
- (void)awakeFromNib
{
[super awakeFromNib];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillEnterFullScreenNotification object:[self _window] queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// lock menubar position when entering fullscreen so It doesn't appear when the mouse is at the top of the screen
_HIMenuBarPositionLock();
}];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillExitFullScreenNotification object:[self _window] queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// unlock menubar position when exiting fullscreen
_HIMenuBarPositionUnlock();
}];
[self _setupToolbarHotspotTrackingView];
}
_setupToolbarHotspotTrackingView is a method on SOToolbar which adds a view to the window, this view will be used to track the mouse location and show/hide the toolbar accordingly.
- (void)_setupToolbarHotspotTrackingView
{
NSView *contentView = [self _window].contentView;
self.toolbarHotspotTrackingView = [[SOToolbarTrackingView alloc] initWithFrame:contentView.bounds];
[contentView addSubview:self.toolbarHotspotTrackingView];
self.toolbarHotspotTrackingView.autoresizingMask = NSViewWidthSizable|NSViewHeightSizable;
self.toolbarHotspotTrackingView.toolbar = self;
}
I also had to override _attachesToMenuBar on SOToolbar so the animation works properly.
- (BOOL)_attachesToMenuBar
{
return NO;
}
SOToolbarTrackingView sets up a tracking area for mouse moved events and checks to see if the mouse is at the top of the window. It then calls some methods on the private class NSToolbarFullScreenWindowManager to show and hide the toolbar.
There's too much stuff to explain It all in detail here, I've uploaded my experimental project so you can take a look. Download the sample project here.
I added a childWindow of a custom subclass of NSWindow to a parentWindow (also a custom subclass of NSWindow). The childWindow has the NSBorderlessWindowMask and canBecomeKeyWindow: is overridden to return YES and canBecomeMainWindow: to return NO.
The childWindow is set to resize with the parentWindow. So I want to create the illusion that the views of the childWindow are part of the parentWindow. The main idea is to arrange the document windows created by the document-based application within a main window to provide a tabbed interface (just like in a browser) to switch between the documents.
My problem is that whenever I click in one of the views of the childWindow, the parentWindow (the main window) looses focus and the traffic light buttons are getting greyed out. This is obviously contrary to what I want to achieve.
I found this answer:
Make NSView in NSPanel first responder without key window status
But even if I override isKeyWindow: (of the main window) to always return YES, the title bar gets greyed out nonetheless when I click into the childWindow.
I also tried to follow this advice:
http://www.cocoabuilder.com/archive/cocoa/143945-non-focused-child-window.html
But I'm not sure what "include the child window in its responder chain just ahead of its nextResponder" means. With canBecomeKeyWindow: to return NO (for the childWindow), the views within the child never can become key and are always greyed out.
Any clue what I am doing wrong?
One addition: Is it possible to make the views in the childWindow FirstResponder without giving the childWindow key-status?
I got this working by mimicking the behaviour of NSPopover. On investigation I found that a popover (which uses a private NSPanel subclass "_NSPopoverWindow") believed it was the key & main window, even though it is not the window returned from [NSApp keyWindow].
Create your own custom NSPanel subclass, attach it to the parent window, and then override the following methods as so:
- (BOOL)isKeyWindow {
return YES;
}
- (BOOL)isMainWindow {
return YES;
}
- (BOOL)canBecomeKeyWindow {
return YES;
}
- (BOOL)canBecomeMainWindow {
return YES;
}
- (void)makeKeyWindow {
[super makeKeyWindow];
[self.parentWindow makeKeyWindow];
}
- (void)makeMainWindow {
[super makeMainWindow];
[self.parentWindow makeMainWindow];
}
- (void)becomeKeyWindow {
[super becomeKeyWindow];
}
- (void)becomeMainWindow {
[super becomeMainWindow];
[self.parentWindow becomeMainWindow];
}
- (void)resignMainWindow {
}
- (void)resignKeyWindow {
}
I am developing an app in which the toolbar can be shown/hide by the user using a button. The problem is the following: If the user chooses to hide the toolbar and then enters the fullscreen mode, the toolbar is shown.
The user interface has been created programmatically (i.e. not using Interface Builder).
This is the toolbar creation in the app delegate:
mainToolbar = [[NSToolbar alloc] initWithIdentifier:MAIN_TOOLBAR];
[mainToolbar setAllowsUserCustomization:NO];
[mainToolbar setDisplayMode:NSToolbarDisplayModeIconOnly];
[mainToolbar setDelegate:self];
[window setToolbar: mainToolbar];
These are the actions performed by the buttons:
-(void)hideToolbar {
editing = YES;
[mainToolbar setVisible:NO];
}
-(void)showToolbar {
editing = NO;
[mainToolbar setVisible:YES];
}
I have tried to fix it using window delegate methods but still the toolbar is shown when entering full screen mode regardless the value of editing.
- (void)windowDidEnterFullScreen:(NSNotification *)notification {
[mainToolbar setVisible:!editing];
}
- (void)windowDidExitFullScreen:(NSNotification *)notification {
[mainToolbar setVisible:!editing];
}
Many thanks in advance!
I could not find a way to maintain the hidden/shown state of the toolbar when the window goes full screen, but you can set the toolbar to always be hidden in full screen, and to animate in when the user goes to the top of the screen. In your window delegate, you can set NSApplicationPresentationOptions to return NSApplicationPresentationAutoHideToolbar in as one of the options. Mine looks like this:
- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
{
return (NSApplicationPresentationFullScreen |
NSApplicationPresentationHideDock |
NSApplicationPresentationAutoHideMenuBar |
NSApplicationPresentationAutoHideToolbar);
}
Here is the relevant documentation: https://developer.apple.com/library/mac/#documentation/General/Conceptual/MOSXAppProgrammingGuide/FullScreenApp/FullScreenApp.html
I load the webview and set allowsScrolling to NO, but webview still shows scroll bars... Banging your head on your computer hurts a lot more now that MacBooks have sharp metal edges.
My code:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
NSString *webFolder = #"file:///<WebFolderPath>";
[[[productWeb mainFrame] frameView] setAllowsScrolling:NO];
[productWeb setFrameLoadDelegate:self];
[[productWeb mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[webFolder stringByAppendingString:#"webpage.html"]]]];
}
I even setup the frame loading delegate to report about the scrolling status:
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
NSLog(#"Scrolling %#",[[frame frameView] allowsScrolling] ? #"Allowed" : #"Not Allowed");
[[frame frameView] setAllowsScrolling:NO];
NSLog(#"Scrolling %#",[[frame frameView] allowsScrolling] ? #"Allowed" : #"Not Allowed");
}
Which still gives me the unhappy:
2010-08-24 15:20:09.102 myApp[30437:a0f] Scrolling Allowed
2010-08-24 15:20:09.104 myApp[30437:a0f] Scrolling Not Allowed
And yet the scrollbars continue to show! Hopefully, it is something stupid I'm doing as I don't want to get any more blood on my laptop.
I found I had to edit the HTML of the page I was trying to display to make sure that it was setup to take the full screen (and not more)... there was a DIV that had a minimum width set. Once I made sure the body had height = 100% and that none of the DIV's had a fixed or minimum width set that was smaller then the box I wanted to show it in everything came together :)
Are you trying to prevent the user from scrolling the view at all? You can just set productWeb.userInteractionEnabled = NO. Or are you just trying to prevent the bars from showing when the user is scrolling?
Here's another thing you can try: inject some JavaScript into your UIWebView that disables the touchmove event:
[productWeb stringByEvaluatingJavaScriptFromString:#"document.ontouchmove = function(e){e.preventDefault();}"];
This leaves the user interaction enabled, but should prevent any scrolling.
Try this if you use Swift:
import Foundation
import Cocoa
import WebKit
class WebViewRep: WebView {
//... hidden code
required init?(coder: NSCoder) {
super.init(coder: coder)
//Disable scrolling
self.mainFrame.frameView.allowsScrolling = false
//Sets current object as the receiver of delegates
self.policyDelegate = self
self.frameLoadDelegate = self
//Load homepage
self.loadHomePage()
}
//... hidden code
override func webView(sender: WebView!, didFinishLoadForFrame frame: WebFrame!) {
//Completely disable scroll
frame.frameView.allowsScrolling = false
self.stringByEvaluatingJavaScriptFromString("document.documentElement.style.overflow = 'hidden';")
}
}
Sadly, it's not enough to use allowScrolling. It works sometimes, but not always. So, you have to manipulate loaded page too.
Of course, don't forget to set WebViewRep as custom class for your WebView.
I'm guessing your web view is in a nib that's being loaded before -applicationDidFinishLaunching: is called.
A quick fix:
In your nib, select the window and deselect "Visible at Launch" attribute.
Then after you call -setAllowsScrolling:, call -[self.window makeKeyAndOrderFront:nil] to show the window.
A better fix is to move your window loading code from the app delegate to a window controller subclass, do the call to -setAllowsScrolling: in -[NSWindowController windowDidLoad], and call -[NSWindowController showWindow:] from your app delegate to show the window.