Files
cappuccino/AppKit/Platform/CPPlatform.j
T
David Richardson eda11e38ba Merge main: Tests/Manual revival, functional fixes
Merges 71 commits from main. Headline content: the Tests/Manual
integration test suite revived and reorganized after long disuse
(renames, new applications, updated cibs), restoring a large
integration validation surface. Functional fixes include replacing
unload-based termination with pagehide (back/forward cache
compatibility) and hardening CPTextField's input-element handling.

Conflict resolutions (local versions retained):

- AppKit/CPTextField.j: main's input-element logic carried, with this
  branch's preprocessor-removal sweep re-applied on top. Main's
  conditionals are re-expressed as runtime CPDOMAvailable guards; the
  _inputElement method-definition gate is retained.

- AppKit/Platform/CPPlatform.j: the DOM platform implementation stays
  inlined under the PLATFORM(DOM) gate. The split layout breaks the
  legacy build: the include fragment is compiled standalone by the
  source walk and cannot resolve its superclass. Main's pagehide
  termination fix is ported into the inlined section; the restored
  AppKit/Platform/DOM/CPPlatform.j fragment is deleted.

Verified: legacy build green through Foundation, AppKit and Tools;
Tests/Manual suite passing.
2026-10-01 14:44:51 -06:00

239 lines
6.1 KiB
Plaintext

/*
* CPPlatform.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@implementation CPBasePlatform : CPObject
{
}
+ (void)bootstrap
{
[CPPlatformString bootstrap];
[CPPlatformWindow setPrimaryPlatformWindow:[[CPPlatformWindow alloc] _init]];
}
+ (BOOL)isBrowser
{
return NO;
}
+ (BOOL)supportsDragAndDrop
{
return NO;
}
+ (BOOL)supportsNativeMainMenu
{
return NO;
}
+ (void)terminateApplication
{
}
+ (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
{
}
+ (void)deactivate
{
}
+ (void)hideOtherApplications:(id)aSender
{
}
+ (void)hide:(id)aSender
{
}
@end
#if PLATFORM(DOM)
// --- begin AppKit/Platform/DOM/CPPlatform.j (inlined; file removed to resolve capp-build basename clash) ---
@global CPApp
if (typeof window["CPPlatformEnableHTMLDragAndDrop"] === "undefined")
CPPlatformEnableHTMLDragAndDrop = NO;
CPPlatformDidClearBodyElementNotification = @"CPPlatformDidClearBodyElementNotification";
CPPlatformWillClearBodyElementNotification = @"CPPlatformWillClearBodyElementNotification";
var screenNeedsInitialization = NO,
mainBodyElement = nil,
elementRemovalTest = new RegExp("\\bcpdontremove\\b", "g");
@implementation CPPlatform : CPBasePlatform
{
}
+ (void)initialize
{
if (self !== [CPPlatform class])
return;
screenNeedsInitialization = [CPPlatform isBrowser];
// We do this here because doing it later breaks IE.
if (typeof document !== 'undefined' && document.documentElement)
document.documentElement.style.overflow = "hidden";
if ([CPPlatform isBrowser])
{
// This differ from cocoa, where shouldTerminate is called in the method terminate of CPApp
// Cappuccino acts like this because we can not close a window openend by the user with a script (so not possible in terminate), and we can only prevent the action in the method onbeforeunload in js.
window.onbeforeunload = function()
{
if ([CPApp _sendDelegateApplicationShouldTerminate] != CPTerminateNow)
return [CPApp _sendDelegateApplicationShouldTerminateMessage];
};
var terminateApplication = function()
{
[self closeAllPlatformWindows];
[CPApp terminate:nil];
};
// "unload" is blocked by the permissions policy in current Chrome and prevents the
// back/forward cache. "pagehide" fires reliably instead. If event.persisted is true the
// page goes into the bfcache and may be restored, so the application must not terminate.
if ("onpagehide" in window)
{
window.addEventListener("pagehide", function(anEvent)
{
if (!anEvent.persisted)
terminateApplication();
}, NO);
}
else
window.onunload = terminateApplication;
}
}
+ (BOOL)isBrowser
{
return typeof window.cpIsDesktop === "undefined";
}
+ (BOOL)supportsDragAndDrop
{
return CPFeatureIsCompatible(CPHTMLDragAndDropFeature) && (CPPlatformEnableHTMLDragAndDrop || ![self isBrowser]);
}
+ (BOOL)supportsNativeMainMenu
{
return (typeof window["cpSetMainMenu"] === "function");
}
+ (void)terminateApplication
{
if (typeof window["cpTerminate"] === "function")
window.cpTerminate();
}
+ (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
{
if (typeof window["cpActivateIgnoringOtherApps"] === "function")
window.cpActivateIgnoringOtherApps(!!shouldIgnoreOtherApps);
}
+ (void)deactivate
{
if (typeof window["cpDeactivate"] === "function")
window.cpDeactivate();
}
+ (void)hideOtherApplications:(id)aSender
{
if (typeof window["cpHideOtherApplications"] === "function")
window.cpHideOtherApplications();
}
+ (void)hide:(id)aSender
{
if (typeof window["cpHide"] === "function")
window.cpHide();
}
+ (DOMElement)mainBodyElement
{
if (!mainBodyElement)
mainBodyElement = document.getElementById("cappuccino-body") || document.body;
return mainBodyElement;
}
+ (void)initializeScreenIfNecessary
{
if (!screenNeedsInitialization)
return;
screenNeedsInitialization = NO;
[[CPNotificationCenter defaultCenter]
postNotificationName:CPPlatformWillClearBodyElementNotification
object:self];
var bodyElement = [self mainBodyElement];
// Get rid of any of the original contents of the page.
var children = bodyElement.childNodes,
length = children.length;
while (length--)
{
var element = children[length];
if (!element.className || element.className.match(elementRemovalTest) === null)
bodyElement.removeChild(element);
}
bodyElement.style.overflow = "hidden";
[[CPNotificationCenter defaultCenter]
postNotificationName:CPPlatformDidClearBodyElementNotification
object:self];
}
+ (void)closeAllPlatformWindows
{
var platformWindows = [CPPlatformWindow visiblePlatformWindows],
primaryPlatformWindow = [CPPlatformWindow primaryPlatformWindow],
platformWindowEnumerator = [platformWindows objectEnumerator],
platformWindow = nil;
while ((platformWindow = [platformWindowEnumerator nextObject]) != nil)
{
if (platformWindow != primaryPlatformWindow)
[platformWindow orderOut:self];
}
}
@end
#else
@implementation CPPlatform : CPBasePlatform
{
}
@end
#endif