AppKit lacked a public text attachment class, preventing rich text documents
from embedding or inserting images.
* AppKit/CPTextView/CPTextAttachment.j:
- Implement CPTextAttachment (modelled on NSTextAttachment) supporting
initialization via data and file type, contents, file types, images,
bounds, and keyed archiving.
- Adopt a TextKit 2-style view rendering architecture that scales images
to fit text container width and triggers layout updates upon asynchronous loading.
* AppKit/CPTextView/CPTextStorage.j:
- Update attributedStringWithAttachment: to accept CPTextAttachment instances
alongside direct views, routing rendering through existing attachment pathways.
* AppKit/CPTextView/CPTextView.j:
- Implement the insertImage: action (invoking browser file pickers) and
Command-V paste handling for images.
- Configure inserted attachments with responsive view instances scaled to
text width, omitting live views during pasteboard archiving.
* AppKit/CPTextView/CPTextContainer.j:
- Adjust attachment bounds to match updated container widths during layout invalidation.
* AppKit/AppKit.j:
- Export CPTextAttachment.
* Tests/AppKit/CPTextAttachmentTest.j:
- Add test coverage for data URLs, archiving, width scaling, insertion,
and serialized text output.
* Tests/Manual/TextEditor/Resources/MainMenu.xib, MainMenu.cib:
- Add Edit > Insert Image… menu item.
* Tests/Manual/TextEditor/WORKLIST.md:
- Mark image insertion testing as completed; log remaining image tasks as open.
Rich text documents now support embedded images inserted via file selection or clipboard paste.
CPTextView previously relied solely on browser clipboard events triggered by
keyboard equivalents, isolating Edit menu actions (Copy, Paste) to an internal
pasteboard. Consequently, menu operations ignored external system clipboard
modifications, and Command-V could mistakenly paste stale internal rich text
following an external copy operation.
* AppKit/CPTextView/CPTextView.j:
- Distinguish menu- and button-driven clipboard actions from browser keyboard event handlers.
- Implement asynchronous Clipboard API integration to write plain text to the system clipboard on copy/cut and read external content for Paste and Paste as Plain Text.
- Implement intelligent clipboard reconciliation: preserve internal rich text if the system clipboard plain text matches, or ingest external system clipboard text (including for Command-V shortcuts).
- Ensure Cut operates correctly across all input vectors.
* Tests/AppKit/CPTextViewTest.j:
- Add unit tests verifying text ingestion and pasting from the system clipboard.
* Tests/Manual/TextEditor/WORKLIST.md:
- Mark Edit menu clipboard synchronization as tested.
- Log rich-text serialization over the asynchronous Clipboard API as an opportunity for future improvement.
Copy, Cut, and Paste operations from the Edit menu now seamlessly exchange plain text with external applications.
AppKit lacked CPTextList and the textLists property on CPParagraphStyle,
preventing rich text from supporting bulleted or numbered lists. Additionally,
CPTextView derived its typing attributes from the character following the
insertion point upon selection changes, causing text appended at the end of a
document (and the Font Panel) to incorrectly revert to default styling.
* AppKit/CPTextView/CPTextList.j:
- Implement CPTextList following NSTextList specifications, including standard
Cocoa marker formats, CPTextListPrependEnclosingMarker, starting item numbers,
markerForItemNumber:, isOrdered, and keyed archiving.
- Add rangeOfTextList:atIndex: and itemNumberInTextList:atIndex: category
extensions to CPAttributedString.
* AppKit/CPTextView/CPParagraphStyle.j:
- Add textLists and setTextLists: properties with copy and archiving support.
- Implement paragraph style equality checks based on list identity.
* AppKit/CPTextView/CPTextView.j:
- Implement setTextList: and the changeTextList: action method (routing marker
styles via sender tags). Adjacent paragraphs with matching styles join automatically.
- Implement list item keyboard navigation and editing mechanics: Return generates
subsequent list items, Return on an empty item terminates list context,
Tab at item origin nests levels, Shift-Tab promotes levels, and Delete at item
text origin strips list membership.
- Automate list item renumbering during live edits, paste operations, and undo/redo cycles.
- Update Paste Ruler routines to correctly synthesize, strip, and merge list markers.
- Fix typingAttributes and Font Panel attribute resolution to derive from the
first selected character or the character immediately preceding the insertion point.
* AppKit/CPKeyBinding.j:
- Bind Shift-Tab selector to insertBacktab:.
* AppKit/CPWindow/CPWindow.j:
- Update key event routing to dispatch Shift-Tab to first responders that accept Tab.
* AppKit/AppKit.j:
- Export CPTextList.
* Tests/AppKit/CPTextListTest.j:
- Add unit test coverage for marker formatting, archiving, list range queries,
interactive list editing, Paste Ruler execution, and menu action validation.
* Tests/AppKit/CPTextViewTest.j:
- Add test coverage verifying typing attributes at trailing insertion points.
* Tests/Manual/TextEditor/Resources/MainMenu.xib, MainMenu.cib:
- Add Format > List menu structures containing bulleted, numbered, and outline choices.
* Tests/Manual/TextEditor/WORKLIST.md:
- Mark list interaction testing as completed; log RTF list serialization as an open item.
CPTextView now provides Cocoa-compliant bulleted, numbered, and nested list support.
CPTextView lacked implementations for copyFont: and pasteFont:
(declared as abstract methods in CPText), causing standard Copy Style and Paste Style menu items to trigger exceptions when invoked.
* AppKit/CPTextView/CPTextView.j:
- Implement copyFont: to copy character attributes (excluding paragraph style, matching Cocoa) of the initial selection character or current typing attributes to the font pasteboard.
- Implement pasteFont: to apply copied character attributes to the selection or typing attributes with undo support, preserving individual paragraph styles.
- Update menu validation logic to enable Copy Style in rich text and Paste Style in editable rich text when the font pasteboard contains valid styling.
* Tests/AppKit/CPTextViewTest.j:
- Add unit tests covering style copying and pasting with and without active selections.
- Add test coverage for menu validation.
* Tests/Manual/TextEditor/WORKLIST.md:
- Record Copy Style and Paste Style as tested.
Copy Style and Paste Style now function consistently with Cocoa.
CPTextView lacked the superscript:, subscript:, unscript:, raiseBaseline:, and lowerBaseline: action methods.
Consequently, standard Baseline menu items targeting these actions were automatically disabled,
even though CPTypesetter and _CPLineFragment already possessed full layout support for baseline offset and superscript attributes.
* AppKit/CPTextView/CPTextView.j:
- Implement superscript:, subscript:, unscript:, raiseBaseline:, and lowerBaseline:.
- Apply attribute modifications to selected ranges or current typingAttributes.
- Register baseline operations with CPUndoManager.
- Implement menu validation logic to enable baseline actions only when the text view is editable and richText is true.
* Tests/AppKit/CPTextViewTest.j:
- Add unit tests for superscript levels and baseline offsets across text ranges and typing attributes.
- Add test coverage for menu validation.
* Tests/Manual/TextEditor/WORKLIST.md:
- Remove resolved baseline management entry.
- Expand documentation on text layout and line fragment drawing.
- Document open items: Justify crash, kerning/ligature settings, and Font Panel integration.
- Note optimal line breaking as a candidate feature for future improvement.
CPTextView had no copyRuler: or pasteRuler:, so Format > Text > Copy Ruler and Paste Ruler did nothing, and ruler changes could not be undone. It now follows Cocoa: Copy Ruler puts the paragraph style at the selection on the ruler pasteboard, Paste Ruler applies it to the selected paragraphs, and every ruler change is registered with the undo manager.
* CPPasteboard.j: Add CPRulerPboardType.
* CPTextView/CPTextView.j: Add copyRuler: and pasteRuler: with validation for rich text; register ruler paragraph style changes with the undo manager; refresh the ruler after a replacement.
* Tests/Manual/TextEditor/WORKLIST.md: Record Copy Ruler and Paste Ruler as tested, and add the Copy Style and Paste Style exception.
nib2cib ignored the text view's Uses Ruler setting, and CPTextView, CPRulerView and CPRulerMarker archived none of their ruler state, so a ruler could not be configured in Interface Builder or survive archiving.
* CPScrollView.j: Set itself as the scroll view of decoded rulers.
* CPTextView/CPRulerMarker.j: Archive the marker's ruler, location, image and image origin, movability, removability and represented object.
* CPTextView/CPRulerView.j: Archive the ruler's orientation, client view, accessory view, markers, thicknesses, origin offset and measurement units.
* CPTextView/CPTextView.j: Archive usesRuler.
* Tools/nib2cib/NSTextView.j, Tools/nib2cib/NSTextViewSharedData.j: Read the Uses Ruler flag.
* Tests/AppKit/CPRulerViewTest.j: Add tests for ruler layout, measurement units, archiving and the Uses Ruler setting.
* Tests/Manual/TextEditor/Resources/MainMenu.xib, Resources/MainMenu.cib: Add the standard Format menu, whose Text submenu shows and hides the ruler.
* Tests/Manual/TextEditor/Resources/DocumentWindow.xib, Resources/DocumentWindow.cib: Rebuild the cib with the ruler setting, and adjust the window's initial position.
CPWindow handled every Tab key press itself and moved to the next key view, so a text view never received Tab and could not insert a tab character.
It now follows Cocoa: an editable text view takes plain Tab and inserts a tab, while Control-Tab, Shift-Tab and Tab in other views still move through the key view loop.
* CPResponder.j: Add _wantsTabKey, which returns NO by default.
* CPTextView/CPTextView.j: Want the Tab key while editable.
* CPWindow/CPWindow.j: Pass plain Tab to a first responder that wants it, and keep the browser from moving its own focus.
The new ruler drew tab stops as L-shaped brackets, which differed from the triangles earlier versions showed, and placed marker images at fractional positions, so identical markers drew differently along the ruler.
* CPTextView/CPRulerMarker.j: Round marker image positions to whole points.
* CPTextView/CPTextView.j: Draw tab stops as triangles pointing right for a left tab, left for a right tab and down for a centre or decimal tab, with whole-point image origins.
* Tests/Manual/TextEditor/WORKLIST.md: Remove the ruler and text layout entries fixed in this series, move the remaining nib2cib ruler entry to the nib2cib section, and record the ruler and text width as tested.
CPTextContainer's line fragment padding was 0 and the typesetter never applied it, so text started 2 points from the text view's edge and ruler markers at 0 were cut off. It now follows Cocoa, with a default padding of 5 points at each end of every line fragment.
* CPTextView/CPTextContainer.j: Default the line fragment padding to 5 points, and archive it.
* CPTextView/CPTypesetter.j: Lay lines out inside the padding: offset line fragment origins by it, compute the right margin, right indent, centred and right alignment within the width inside it, and subtract it when layout resumes from a stored line fragment.
* CPTextView/CPTextView.j: Start the caret in empty text inside the padding.
A text container that tracked its text view's size took the text view's full width, while the text started after the text container inset, so lines could run past the visible right edge.
It now follows Cocoa: a tracking container fills the text view minus the inset on both sides.
* CPTextView/CPTextContainer.j: Subtract the text container inset on both sides when tracking the text view's width and height.
* CPTextView/CPTextView.j: Refit the text container when a text view is created and when its text container inset changes.
Ruler classes departed from canonical NS versions, resulting in functional and visual gaps.:
markers were views that drew text characters and ignored their location argument, the ruler rebuilt its subviews on every update and had no origin offset, measurement units or reserved thicknesses, and CPTextView updated the ruler only on focus and typing attribute changes, had no ruler control methods, and never showed a right indent marker.
* AppKit.j: Import CPRulerMarker and CPRulerView.
* CPScrollView.j: Tile rulers by their required thickness, and give a ruler its scroll view when it is set.
* CPTextView/CPRulerMarker.j: Add CPRulerMarker as an object drawn by its ruler, with a marker location, an image and image origin, movability and removability, and tracking that adds, moves and removes markers through the client view.
* CPTextView/CPRulerView.j: Rewrite CPRulerView with an origin offset, registered measurement units defaulting to the user's region, reserved thicknesses for markers and an accessory view, Cocoa's client view methods, temporary ruler lines, and drawing in a single pass.
* CPTextView/CPTextView.j: Add usesRuler, isRulerVisible, setRulerVisible: and toggleRuler: with a Show Ruler or Hide Ruler title; update the ruler on every selection change; place tab stop, first line, head and tail indent markers relative to the start of the text, with SVG marker images and a context menu for changing tab types and resetting indents.
* Tests/Manual/TextEditor/DocumentWindowController.j: Show the ruler through setRulerVisible:.
A text view handled undo: and redo: and registered its changes even when allowsUndo was NO, so Edit > Undo stayed enabled and did nothing.
Behaviour now follows canonical Cocoa: a text view that does not allow undo registers nothing and passes undo: and redo: on to the window, and Undo and Redo are enabled only when there is a change to undo or redo.
* CPTextView/CPTextView.j: Register changes only when undo is allowed, stop responding to undo: and redo: when it is not, and validate the Undo and Redo items against the undo manager.
* CPWindow/CPWindow.j: Validate the Undo and Redo items against the window's undo manager.
* Tests/AppKit/CPTextViewTest.j: Add tests for responding to undo:, registering changes and validating the Undo item.
* Tests/Manual/TextEditor/DocumentWindowController.j: Add toggleAllowsUndo: and validateMenuItem:, so that undo can be turned on and off for the active document.
* Tests/Manual/TextEditor/Resources/MainMenu.xib, Resources/MainMenu.cib: Add Edit > Allow Undo.
* Tests/Manual/TextEditor/WORKLIST.md: Remove the entry for this gap, record Allow Undo as tested, and add the key equivalent behaviour of disabled menu items for discussion.
- CPTextField, CPTokenField, CPTextView: the PLATFORM(DOM) gates
around _inputElement (superclass and override) and _cumulativeOffset
are removed; the methods now exist under both targets with runtime
CPDOMAvailable guards returning nil (object methods) or a zero
point (struct method) when no DOM is present
- contract change: under CommonJS these methods change from absent to
present-and-inert; all callers are browser event paths never
exercised by the theme blender or nib2cib
- zero preprocessor directives remain in these three files
- work-in-progress towards complete removal of CPP directives
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.
Cappuccino previously supported three platform contexts behind the
PLATFORM() preprocessor macro: Browser, CommonJS/Node, and a NativeHost
target. NativeHost is no longer supported; this removes it and
consolidates on Browser (for the app) and CommonJS/Node (still needed
by the toolchain itself, for theme compilation and testing).
PLATFORM(DOM) conditionals throughout AppKit governed both distinctions
at once - Browser vs NativeHost, and separately, DOM-dependent code vs
the CommonJS/Node build. Each conditional was reviewed individually:
NativeHost-only branches were removed, while branches needed for
CommonJS/Node were kept intact rather than collapsed to Browser-only.
Also included, found in the course of this work:
- Fixed two pre-existing duplicate instance-variable declarations
(_ephemeralSubviews in CPView, _scrollingTimer in CPTextView)
- Added a missing @import for CPTextContainer.j in CPTextView.j so
it resolves when compiled outside the full framework bundle
- Merged two Platform/DOM/*.j files into their parents to resolve a
build-tool basename collision, preserving the CommonJS fallback path