{"id":13798417,"url":"https://github.com/gluonhq/rich-text-area","last_synced_at":"2025-04-05T08:05:44.680Z","repository":{"id":38444363,"uuid":"449081774","full_name":"gluonhq/rich-text-area","owner":"gluonhq","description":null,"archived":false,"fork":false,"pushed_at":"2025-03-12T14:51:32.000Z","size":55258,"stargazers_count":123,"open_issues_count":44,"forks_count":16,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-03-29T07:07:34.392Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gluonhq.png","metadata":{"files":{"readme":"README-impl.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-17T23:45:22.000Z","updated_at":"2025-03-27T13:08:47.000Z","dependencies_parsed_at":"2024-04-03T09:30:20.647Z","dependency_job_id":"891e7bdf-c2fd-4fd5-bd04-3ac8adc24296","html_url":"https://github.com/gluonhq/rich-text-area","commit_stats":{"total_commits":194,"total_committers":10,"mean_commits":19.4,"dds":"0.37628865979381443","last_synced_commit":"501ff698918b55dac4e016a989df179a6cfa6b99"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gluonhq%2Frich-text-area","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gluonhq%2Frich-text-area/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gluonhq%2Frich-text-area/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gluonhq%2Frich-text-area/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gluonhq","download_url":"https://codeload.github.com/gluonhq/rich-text-area/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247305933,"owners_count":20917208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T00:00:43.517Z","updated_at":"2025-04-05T08:05:44.659Z","avatar_url":"https://github.com/gluonhq.png","language":"Java","funding_links":[],"categories":["Java","Community","Libraries, Tools and Projects"],"sub_categories":["Libraries"],"readme":"# The Rich Text Area Project - Implementation Details\n\nThis document will shed some light into the implementation details of the project\nto make it easier for developers to understand and contribute back to it.\n\nWe'll discuss some important classes:\n\n## RichTextAreaSkin\n\nContains the skin/view of the control.\n\nThe skin contains just one child aka `ParagraphListView`, which is a custom `ListView` and contains `RichListCell`\nto represent each `Paragraph` in the TextArea. Each of these Paragraph can contain a Text along with Emojis, Image or a Table.\n\n## Document\n\nDocument is the basic model that contains all the information required for the RichTextArea control,\nin order to render all the rich content, including decorated text, images and other non-text objects.\nA document is basically a string with the full text, and a list of DecorationModel that contain the text and paragraph decorations for one or more fragments of the text,\nwhere a fragment can be defined as the longest substring of the text that shares the same text and paragraph decorations.\nAny change to the document invalidates the undo/redo stack, forces the RichTextAreaSkin to recreate the `PieceTable` and sets it on the `RichTextAreaViewModel`.\n\n## Decoration\nDecorations are changes that can be performed on RTA’s fragments like Text, Image, Table etc.\n\n### TextDecoration\nTextDecorations are the simplest decorations that can be applied to Text fragments and can be used to change the font family, weight, size, color etc. of the text.\n\n### ImageDecoration\nImageDecorations can be used to change the width and height of an Image. It can also be used to add a hyperlink to the image.\n\n### TableDecoration\nDecorations related to a Table: number of rows, columns and text alignment of each of the cells.\n\n### ParagraphDecoration\nDecorations which can be applied directly at a paragraph level. For example, text alignment, indentation, line spacing etc.\n\n## AbstractCommand\n\nAbstractCommand is an internal API in the `com.gluonhq.richtextarea.undo` package, so basically it is a way of saying that everything done under it can be redone/undone, and the `CommandManager` will take care of it.\nThis is an internal API, not exposed to the users, and it deals directly with PieceTable.\nEach implementation define a command or group of commands that will be applied in a batch operation, so they can be undone/redone in a single call.\n\nTypically, these actions can be broadly categorised into:\n\n### Normal actions\nActions like insert, append, replace, delete \n\n### Decorate actions\nActions like text, image, table, paragraph\n\n## ActionCmd\n\n`ActionCmd` is pretty much the public API for accessing the same private API which are present in `AbstractCommand`.\nIt defines actions, commands, or operations that the user can perform over the control, like the same above.\n\nHere are few actions that the user can execute:\n\nnew, open, save\ncut, copy, paste,\nselect,\nundo, redo\ncreate table\n\n## CommandManager\n\nCommandManager is responsible for the undo/redo actions performed in RTA.\nIt contains a stack containing all the actions performed by the user, so that at any point of time these actions can be undone via undo, or re-executed via redo actions.\n\n## Design Notes\n\nComponent's internal design is based on MVVM pattern.\n\n### Model aka TextBuffer and its implementations\n\nThe data model is based on piece table implementation, which helps to easily deal\nwith huge texts and simplifies to some extent undo functionality. It implements insert,\nappend and delete text operations and a simplistic change listening. Within the piece table\nchanges are represented by one or more pieces. Piece does not contain the text itself but points\nto one of two buffers: original - fixed original text, additional - \"add only\" buffer for changes.\nActual text can be restored by walking the pieces. Each piece can contain text, image, table, or paragraph\ndecoration. The model also implements an undo/redo mechanism which uses pieces but is based on\nabstract independent API (which is reused ViewModel too). Each document operation is represented\nas a command, which stores the state and can be undone/redone.\n\n### ViewModel aka RichTextAreaViewModel\n\nThis is where all the “business” logic is concentrated, fully independent of the view. Given the text\nbuffer(model) it can manipulate it by either executing predefined actions or internal methods.\nInternally, some of its actions are using builtin undo/redo manager again, since in addition\nto manipulating text, we have to deal with additional state - caret position and text selection.\nActions are independent of keyboard shortcuts, which are defined in the view, and in theory\ncan even allow us to define custom keyboard mappings for the component in the future, kind of like IDEs do.\n\n### View aka RichTextAreaSkin\n\nThe view is where all this comes together. Currently, implementation of the view is based on TextFlow,\nbut it can be anything (Canvas for example, if TextFlow proves to be not performant enough for texts\nwith a lot of  fragments). View can react on changes within ViewModel and also ask view model to execute actions.\nFor example, when caret position or text selection changes in viewModel, view reacts and represents them visually.\nIt also has a (currently fixed) map of keyboard shortcuts to actions. Those actions are then executed by those shortcuts\nautomatically.\n\nThe view also supports some mouse operations already, like:\n\n- Move the caret and select text\n- Select a word by two clicks\n- Select a paragraph with three clicks\n\nCurrently, each document change refreshes the whole text flow, which is very inefficient,\nbut that can change later, once the design is ironed out.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgluonhq%2Frich-text-area","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgluonhq%2Frich-text-area","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgluonhq%2Frich-text-area/lists"}