All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog.
The API is unstable, and Semantic Versioning does not yet apply.
Changes in master that are not yet released. Click to see more.
- Fixed restoring from minimized state with
win.restore()
, when a taskbar. (The minimize button was not broken, as it usedminimize()
to restore the window, which currently toggles the minimized state.)
- Accessing jQuery methods/properties on
$Window
instances is deprecated. Use theelement
property to access the underlying DOM element, and wrap it in a jQuery object if you wish to use jQuery methods.- A deprecation notice will be logged each time a jQuery method or property is accessed on a
$Window
instance, with a stack trace. In some cases, it will recommend a specific alternative. - In TypeScript definitions, the jQuery methods and properties are mapped to
never
, with some common methods/properties given special deprecation notices.
- A deprecation notice will be logged each time a jQuery method or property is accessed on a
- jQuery events on
$Window
instances are deprecated. Use theonBeforeClose
andonClosed
methods to add event listeners.- A deprecation notice will be logged when a listener is added using jQuery's
.on()
method, along with a stack trace, and the appropriate method to use instead.
- A deprecation notice will be logged when a listener is added using jQuery's
$Window
function now returns aProxy
object, to aid with the transition away from jQuery.- The API is the same, but I've begun to separate the jQuery out from the
OSGUIWindow
interface internally, by overlaying the methods/properties of a jQuery object onto an object satisfying theOSGUIWindow
interface. - Eventually,
OSGUIWindow
will become a class, and$Window
will be deprecated/removed.
- The API is the same, but I've begun to separate the jQuery out from the
$Window
propertyelements
for accessing the different parts of the window, without jQuery.content
: The window's content area.titlebar
: The window's titlebar, including the title, window buttons, and possibly an icon.title
: The window's title.closeButton
: The window's close button.minimizeButton
: The window's minimize button.maximizeButton
: The window's maximize button.
- A simplified event system for
$Window
instances, independent of jQuery. Each of these methods returns a function that removes the listener.$Window
methodonFocus(listener)
$Window
methodonBlur(listener)
$Window
methodonIconChange(listener)
$Window
methodonTitleChange(listener)
$Window
methodonClosed(listener)
$Window
methodonBeforeClose(listener)
- The listener is passed an object with
preventDefault
which can stop the window from closing.
- The listener is passed an object with
$Window
methodonBeforeDrag(listener)
- The listener is passed an object with
preventDefault
which can prevent the drag.
- The listener is passed an object with
- A window element will have a CSS class
minimized
when minimized, ifsetMinimizeTarget
was called before minimizing.
0.7.3 - 2024-06-15
- Fixed positioning of windows when minimized without a taskbar.
- Fixed menu bar visibility when window is minimized without a taskbar. (It was typically offscreen, but you could reveal it by dragging the window.)
- Closing a window now frees up its minimize slot at the bottom of the screen (if there's no taskbar). Previously only unminimizing did this.
0.7.2 - 2024-05-29
- Marked
options.element
andoptions
as optional inapplyCSSProperties
type declarations. - Added missing
force
parameter to$Window
'sclose
method in type declarations and documentation. - Changed
getIconAtSize
return type toNode | null
(fromHTMLElement
) in type declarations, and mentioned that it can returnnull
in the documentation. - (Also changed type of
private $icon
toJQuery<Node>
) - (Added
dock
method requirement to deprecated$component
option of$Window
constructor, in type declarations.) - (Removed weird
$G.off("scroll", onscroll);
for non-existentonscroll
in$Window.js
. This didn't cause an error, sinceonscroll
is a global event, but it shouldn't have been there.)
0.7.1 - 2024-05-24
- Fixed an assertion error that was thrown when navigating menus with the keyboard, due to an overly broad condition. (I asserted that the type was HTMLElement, but needed to assert that it was either null or an HTMLElement. The assertion was just for type narrowing.)
0.7.0 - 2024-05-23
- Deprecate
item
in favor oflabel
for menu item labels- This is just a clearer name for the property.
- Deprecate
shortcut
in favor ofshortcutLabel
andariaKeyShortcuts
aria-keyshortcuts
needs "Control" spelled out, and for macOS "Meta" for the command key, unlike the traditional visual representations. Hence the separation of concerns.
AccessKeys
API for parsing and rendering labels with access keys (syntax:&
defines the following character as the access key,&&
inserts one literal ampersand)AccessKeys.escape(label)
escapes ampersands by doubling themAccessKeys.unescape(label)
unescapes ampersands by removing one of each pairAccessKeys.has(label)
returns whether the label has an access keyAccessKeys.get(label)
returns the access key character, ornull
if there isn't oneAccessKeys.remove(label)
returns plain text without access key indicator, likeAccessKeys.toText()
but with a special case to remove parentheticals such as " (&N)" rather than just the ampersandAccessKeys.toText(label)
returns plain text without access key syntaxAccessKeys.toHTML(label)
returns HTML with<span class="menu-hotkey">
around the access key (usesAccessKeys.toFragment
for security)AccessKeys.toFragment(label)
returns aDocumentFragment
with<span class="menu-hotkey">
wrapping the access key character- private
AccessKeys.indexOf(label)
(don't use this) - (In the future, the CSS class "menu-hotkey" may be renamed to "access-key", perhaps with a prefix.)
- Radio menu item support
- TypeScript types for the whole library
- Type declarations are included as part of the
os-gui
package, inos-gui.d.ts
- You may need to reference the declarations file explicitly in your
tsconfig.json
'sinclude
orfiles
array, or use a/// <reference path="node_modules/os-gui/os-gui.d.ts" />
directive. I'm not sure how exactly this is supposed to work.
- Type declarations are included as part of the
$Window
methods:- experimental
onFocus
,onBlur
, andonClosed
API for events (looking to remove dependency on jQuery) - private
addChildWindow($window)
(don't use this) - private
unminimize()
(don't use this)
- experimental
$Window
properties:closed
: Whether the window has been closed.icons
: The icons of the window at different sizes, as set byoptions.icons
orsetIcons()
.$minimize
: the minimize button$maximize
: the maximize button- private
$title_area
(don't use this) - private
$icon
(don't use this)
$Window
propertyelement
(already mentioned but now has a section like other properties)- Menu item specification properties:
shortcutLabel
for defining the label of the shortcut key combination separately from theariaKeyShortcuts
property; this replaces the oldshortcut
propertyariaKeyShortcuts
for defining the access key combination for the menu item. Must follow aria-keyshortcuts syntax.label
for defining the label of the menu item; this replaces the olditem
propertyvalue
(only for radio items) for defining a radio option value
- Docs for positioning windows
- Handle synthetic events, including when pointerId is not given
- This is for jspaint, which triggers pointerup when pressing both mouse buttons to cancel a drawing gesture, and on blur.
- Make menu bars wrap to multiple rows when needed
- Close menus if focus leaves menu popups and menu bar
- If you click on the empty space on the menu bar, it should close menus, not just unhighlight.
- This also seems to fix the case where a window is closed while menus are open (you can test this with the Trigger Station in test.html)
- Improve menu bar code and some behavior
- Prevent some unnecessary DOM updates with highlighting and opening/closing.
- Check for specific menu bar instance when testing focus
- Make menu bar only ever close its own menu popups
- Reduce redundancy in menu closing code
- Fix cycling behavior with Up key: pressing up in a menu opened by clicking (such that the first item isn't automatically highlighted) now goes to the bottom item, instead of the top item (or the second-to-bottom item if you had hovered a menu item within and then moved the mouse out). It still focuses the top item if you open the menu via up/down arrow as this matches the Windows 98 behavior for using the keyboard.
- This commit might actually break closing menu popups in the case that the menu bar is removed from the DOM, because it relies on sending events...
- (I'm not sure if I followed up on this.)
- Use event.key instead of event.keyCode
- Prevent entering disabled submenus [with the keyboard?]
- Don't dispatch update events when hovering menu items
- This only affects the Schrödinger's Checkbox as far as I know, and arguably makes it more thematic, since it only changes when "observing" it.
- (Should it be called Schrödinger's Tick, btw? haha, gross.)
- Make menu popups inherit the theme from the menu bar
- Patch drag handling for Eye Gaze Mode in JS Paint
- Fix menu button border offset on press, and oscillating menu opening when hovering between two menu buttons
- Fix: keep menu button highlighted if clicked to close
- Highlight/open menus when moving mouse at all while over menu button
- Fix: don't trigger menu items if holding Ctrl
- For example, in Paint, with the Help menu open, Ctrl+A shouldn't open About Paint, it should Select All, using the app-global keyboard shortcut.
- SVG icons for checkbox/radio/submenu icons are now defined in CSS using
mask-image
- Fix subpixel issues with menu button borders, and margin-bottom (and greatly simplify, by adding a wrapper span)
- Refocus last focused control outside menus on close to support copy/paste
- This generalizes refocusing the last focused control within the window to also work for controls outside the window, I think?
- Fix setting window title to empty string
- Previously, it returned the current window title instead of clearing it, due to incorrect handling of falsy values when differentiating between getter/setter method signatures.
MenuBar
menu item propertydescription
is now optional.
see Changed
0.6.0 - 2021-11-01
$window.task
way of interfacing with a taskbar. Use$window.setMinimizeTarget(taskbarButtonElement)
instead, and eventsicon-change
andtitle-change
to update the button.
MenuBar
methodcloseMenus()
to close any open menus.MenuBar
methodsetKeyboardScope(...elements)
to control hotkey handling$Window
methodsetMenuBar(menuBar)
to set the menu bar, and set up the keyboard scope.$Window
methodsetMinimizeTarget(taskbarButtonElement)
to set the element representing the window when minimized, which will be used when animating.$Window
propertyelement
to get the DOM element.element.$window
to get the$Window
instance from the DOM element.$Window
eventsicon-change
andtitle-change
- Top level menus support access keys without holding Alt, if the menu bar is focused. (You can not yet tap Alt to focus the menu bar, so you're probably still going to need to hold Alt in practice for now.)
makeBlackToInsetFilter()
inparse-theme.js
to initialize an SVG filter for disabled button icons
- If you close a menu by clicking the menu button, the containing window will now be re-focused.
- Menus no longer close when encountering a synthetic
blur
event, to facilitate a hack in Pinball, where ablur
is triggered to trick the game into pausing. - Windows that are not
resizable
can no longer be maximized. The maximize button will be grayed out.
- Fixed error when pressing arbitrary (unhandled) keys with menu bar focused
- Menus now ignore Alt+(hotkey) if the event is already handled. (For instance, on the demo page there's a menu bar without a window which has global hotkeys, as well as menu bars with identical hotkeys in windows. Hotkeys will now affect the appropriate menu bar depending on whether a window is focused.)
- Window titlebar buttons now use
ButtonText
theme color instead of always black.
0.5.0 - 2021-10-29
$Window
's terribleoptions.icon
API. Use the new, versatileoptions.icons
instead. No more ugly globals you have to define! Example:new $Window({icons: {16: 'app-16x16.png', any: 'app-icon.svg'}})
setIconByID()
, usesetIcons(icons)
instead (with same format asoptions.icons
)getIconName()
, use$window.icons
instead perhaps, or avoid it entirely
applyCSSProperties
now takes an options object instead of an element as the second argument. Useoptions.element
to specify the root element. Default isdocument.documentElement
(i.e.<html>
,:root
).applyCSSProperties
now accepts aCSSStyleDeclaration
interchangeably with a plain object of CSS properties, same asrenderThemeGraphics
does. I don't know if this is useful, but it's good to be consistent, and this doesn't cost much.- Page scrolling is prevented when the window is re-focused. (Browsers by default scroll controls into view, and re-focusing the window focuses the last focused control.)
touch-action: none
is now applied to the menu bar, so the page doesn't scroll if you're trying to access the menus.- Menus now close on pointer down, not pointer up, for menu buttons.
- When windows are minimized without a taskbar, the minimize button now shows a restore icon.
- Taskbar height calculation now includes padding/border (of
.taskbar
element) - When a menu item is clicked and the menu closes, the containing window is re-focused.
$Window
'sclosed
event wasn't fired because the element was removed from the DOM.- A non-
toolWindow
window withparentWindow
defined now shows as focused. aria-owns
attribute now correctly uses element IDs (not stringified elements like[object HTMLDivElement]
)- Super minor: if a menu bar is contained in a selection, it will no longer show access key underlines as white. This bothered me. What can I say, I'm a compulsive highlighter.
- Handle older jQuery for
pointerId
((e.pointerId ?? e.originalEvent.pointerId)
); affects the cursor during window resizing (which usessetPointerCapture
to keep a consistent cursor). - Fix restore from minimize (to taskbar) going to top left corner of screen (if the window had previously been dragged). (This does not apply to taskbarless minimization, which seems to be fine.)
- Word wrap is now prevented in flying titlebar text.
- Menu bar behavior with touch (menus not opening, dialogs blurring after opening via menu, etc.)
- Prevented showing multiple menu buttons as hovered (e.g. if you press Esc and left/right and then hover a different item with the mouse)
- Prevented focus ring showing on menu items when clicking and then using the keyboard, or when using touch. (Menu item highlight effect is separate from focus ring.)
- Prevented resizing window while minimized to bottom of screen (in the case that there's no taskbar).
- Prevented titlebar from shrinking and disappearing (especially when minimized without taskbar), for some window layouts.
- Fixed animation of window restoring if window was minimized without taskbar and then dragged.
- Fixed titlebar button active state not working in Chrome 95.
- Don't show padding around window when window is maximized.
- Windows are now shown as focused when focus is within an iframe, even for nested iframes! Unfortunately this can't work for cross-origin iframes in all cases. (For 98.js.org this was a regression in v0.4.0 due to focus handling changes, but now it's handled in the library)
- Focus can now be restored to the last focused control within (same-origin) iframes, even nested iframes! (when refocusing windows, e.g. clicking on the titlebar)
options.iframes.ignoreCrossOrigin
to silence warnings about cross-origin iframes (which can't be seamlessly integrated).applyCSSProperties
now supportsoptions.recurseIntoIframes
(defaults tofalse
).$Window
methodsmaximize()
,minimize()
, andrestore()
$Window
optionicons
which can specify icons of different sizes. Pass an object with keys that are sizes in pixels (or "any"), and values that are the URL of an image, or an object withsrcset
if you want support different pixel densities, or a DOM node if you want full control (e.g. to use an<svg>
or a font icon or an emoji text node).$Window
methodsetTitlebarIconSize
to set the icon size, picking the nearest size fromicons
.$Window
methodgetTitlebarIconSize
to get the current icon size.$Window
methodgetIconAtSize
to pick an icon for the given size, for use in a taskbar. Returns an element ornull
.$Window
now exposesicons
property based on theoptions.icons
option..pressing
class to show buttons as pressed (when triggering via the keyboard for example).
0.4.1 - 2021-10-20
- Ability to use
MenuBar
without$Window.js
(TypeError: Assignment to constant variable.
) - Handle
document.body
not existing if you create aMenuBar
beforeDOMContentLoaded
- Compatibility with older jQuery
- Removed some redundant event listeners
- More elements are considered tabbable (
object
,embed
,video
,audio
,iframe
,[contenteditable]
) - Greatly improved performance while hovering menu items! Focus is now only set on the menu popup, not the menu item.
- Menu item height no longer changes based on checkbox state
- Menu items that have a submenu open are now highlighted unless another item is hovered at that level.
- If you hover to open a submenu, and then press right (in LTR layout, or left in RTL), it will no longer go to the next top level menu. The submenu is already focused, so you can use up/down to navigate it.
- SVG is now used for checkbox menu items, instead of text.
- SVG for submenu arrow is now more accurate to Windows 98.
- Menu item and divider height is now accurate to Windows 98.
- Menu bars are now screen-reader-friendly!
info
events (for status bar updates) are now sent when using the arrow keys to navigate.- If a submenu is empty, it is shown with "(Empty)", grayed out.
0.4.0 - 2021-10-15
minWidth
option; useminOuterWidth
instead.minHeight
option; useminOuterHeight
instead.- global
window.focusedWindow
(not part of API)
$MenuBar.js
; useMenuBar.js
instead. jQuery is no longer used by the menu bar module.$MenuBar(menus)
; usenew MenuBar(menus).element
instead.- The extra parameter to menu bar's
info
event; useevent.detail?.description
instead.
parseThemeFileString
can now returnundefined
if the theme file is not valid.- HTML
dir
attribute / CSSdirection
property is now respected at the level of the window/menu bar, rather than just the document body, so you can have individual windows with different directions. - Menu bar's buttons and top level menus are no longer contained in a
<div class="menu-container">
element. Top level menus are now children of<body>
, as submenus already were. - Clicking on window will now focus not just the last focused element, but if there wasn't one, it will focus a control with
class="default"
, and if that doesn't exist, the first control, and if there's no controls, the window itself (specifically$window.$content
) or a tool window's parent window. $window.focus()
now actually focuses something, rather than just bringing the window to the top and making it appear active. It will focus the last focused control within the window, or else a control withclass="default"
, or else, if it's a tool window, the parent window, and otherwise the window itself (specifically$window.$content
).$window.blur()
now removes focus from any focused control within the window. If focus is outside the window, it's not changed.- Windows can now be positioned freely when the
<body>
element is smaller than the viewport. The boundary is considered to be the maximum of the document's scrollable area and the viewport. - Window focus is now based around DOM focus. Focusing a control within the window will automatically focus the window. Special logic for preventing blur for taskbars is removed. To prevent blur you must now listen for
mousedown
orpointerdown
on your element and callevent.preventDefault()
, the standard way to prevent blur. - Tool windows that have no parent window are now shown as focused as long as the browser window is focused. This is useful for web applications where the browser window takes the place of the parent application window.
- Window method
setDimensions({ innerWidth, innerHeight, outerWidth, outerHeight })
to set the size of the window. - Window options
innerWidth
,innerHeight
,outerWidth
,outerHeight
to set the initial size of the window. - Window options
minInnerWidth
,minInnerHeight
,minOuterWidth
,minOuterHeight
to set the minimum size of the window. - Windows can now be minimized without a taskbar.
- Menu bar's
info
event now works with submenus as well. (Previously items that contain submenus were assumed to not have descriptions, simply because Paint's one submenu does not a have a description. But for instance Explorer has descriptions for all of its menus (except Favorites, which is a bit special, what with drag and drop and context menus and all.)) - Greatly improved menu navigation:
- Menus can now be opened with Enter and exited with Escape.
- Menus can now be navigated with access keys, and the first letters of items without access keys defined.
- Pressing Escape an extra time will unfocus the menu bar, focusing the last focused control within the window.
- Submenus can now be navigated with the arrow keys.
- Submenus stay open more easily. It's a little buggy still, but they're not constantly trying to close themselves on you.
- Menus wrap around when navigating up and down or left and right.
- The default action of scrolling the page with arrow keys is now prevented when menus are focused.
- Improved accuracy of the titlebar styles, especially for tool windows.
- Fixed active state of the titlebar buttons in Firefox.
- Disabled buttons no longer show active state if you try to click on them.
- In demo: When loading a theme file, do not apply any styles if it is not a valid theme file.
- For right-to-left languages, submenus are now opened with the left arrow key, matching the arrow direction shown, and menus are navigated with left/right arrow keys spatially (before it was swapped because the order of elements was reversed but the key bindings were not).
- Titlebar gradient is flipped for RTL languages.
- Submenus have correct RTL layout. (Top level menus were previously descendants of the window (so I didn't notice the problem), but now all menus are children of the document body, and
dir
attribute is propagated from the menu bar element'sdirection
CSS property to the floating menus.) - Focused disabled menu items are distinguished from enabled menu items.
0.3.0 - 2021-09-04
- Added window options
toolWindow
,parentWindow
,maximizeButton
,minimizeButton
,closeButton
,resizable
,minWidth
,minHeight
, andconstrainRect(rect, x_axis, y_axis)
. - Added window method
bringTitleBarInBounds()
. - Added window event
closed
, which should be used instead ofclose
for detecting when the window is closed. Useclose
only for preventing the window from closing. - Added window event
window-drag-start
. - Focus wrapping now works with Shift+Tab in addition to Tab, and handles more types of focusable elements.
- Focus is now restored to the last focused element within the window when the window is focused again.
- Focus is now given to the next-topmost window when the window is closed.
- Loosened constraints on windows when releasing a drag. You can now drag a window out of the screen, except the titlebar is kept in bounds. (This still doesn't match the behavior of Windows, but in Windows you can recover a window from offscreen with Alt+Space or the taskbar context menu.)
- Increased thickness of the window frame to match the look of Windows 98.
- Window overflow is now hidden by default, with
contain: layout paint;
on.window-content
in the layout CSS. - Window content now flexes to fill the window, with
flex: 1;
in the layout CSS. The$content
element still uses the default box model (i.e.display: block
), but is stretched within its parent which usesdisplay: flex;
.
- Use standard
touch-action
CSS property instead of obsolete PEP polyfill's attribute. The PEP library was never included or documented as a dependency. - Keyboard shortcuts using the meta key are no longer swallowed by the window.
- Allow setting title to empty string. Not very useful.
0.2.2 - 2020-04-30
- Added a Blue color scheme for use in JS Paint for the Winter theme.
- The menu bar is now a fixed height, which should help with automated visual regression testing in JS Paint.
- Submenu popups are now offset correctly on scrollable pages (such as the demo)
- Windows are now clamped to the bounds of a scrollable page instead of an area the size of the view at the top of the page
- Windows are now centered correctly in view when the page is scrolled
- Windows are now dragged correctly while scrolling the page
- Unwanted globals
$G
andE
are no longer exported
- Windows are bounded to the screen at the end of a drag operation. This doesn't match behavior of windows in Windows 98, but in lieu of OS features for getting windows back on screen like Alt+Space, I think this makes sense for now.
- Dragging over iframes is fixed
- Some layout-important CSS is moved to
layout.css
- Some titlebar-related styles are scoped in to
.os-window *
to fix conflicts in jspaint, where I'm trying to use a separate window class temporarily for tool windows. - Colors:
- Menu bar dividers now correctly use the theme colors
- Disabled buttons now correctly use the theme colors
- Disabled menu items now correctly use the theme colors except that sometimes it should just show GrayText and not a 3D effect
- Menu bar button text uses the correct colors now
0.2.0 - 2020-03-12
- Rewrote using PostCSS
- Everything is now themeable, by dragging and dropping
.theme
and.themepack
files - Maximize and Minimize, with flying titlebar effect
- Default buttons
- Toggle buttons
- Button borders are now based on SVG
border-image
, instead of using pseudo elements,border
andbox-shadow
.- Metrics for buttons are changed, they're simpler now, because it's not extending visibly outside the border-box.
- (
::after
is now free to use for other things, altho::before
is still used for showing focus.)
- Window component is now an app window instead of a tool window, to aid reintegration with 98.js.org; jspaint will come later.
- Window component is styled with
.os-window
now, altho it includes both classesos-window
andwindow
.