Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ The product is the generated class. It must:
in `src/ui/store.js`, the same list in `preview.html`, which takes any
host only when the editor frames it). Any other host comes from the UI5
field, typed by the user. Never widen the list for a link.
- An edit on the selection (delete, duplicate, move, wrap, select the
parent) is written once, in `src/ui/actions.js`, and works on every
selected control; the keys, the command palette, the canvas toolbar and
the context menu (`src/ui/context.js`) call it. A question to the user goes through `choose( )` in
`src/ui/dom.js`, never the browser's `confirm( )`.
- The preview module (`src/preview/init.js`) runs inside UI5 1.71: ES5
style, `sap.ui.define`, no API newer than 1.71.

Expand Down
69 changes: 58 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ Also in the editor:
attributes the data, `client->_event( )` the event names. Export writes
the chain back into that class and leaves every other line as it was;
new attributes go to the end of the public section, new events get a
`WHEN` branch in `on_event`. A view attribute the editor cannot edit
`WHEN` branch in `on_event`. The *Changes* tab next to the class shows,
line by line, what the export changes in the class as it was opened. A
view attribute the editor cannot edit
(`client->check_app_prev_stack( )`, a `COND #( )`, an `id`) is kept as
ABAP on its control and written back unchanged; the dialog after the
import lists it, and lists what could not be imported at all (a public
Expand All @@ -113,19 +115,63 @@ Also in the editor:
extension (`vscode://abap2ui5.abap2ui5/open`), which opens it as an
unsaved `.clas.abap` and offers to run it.
- **Save / Open** stores the design as JSON so you can continue later. The
design is also kept in the browser between visits; what New, Open or
Import replaced is under *Recent designs*. **Copy share link** puts the
whole design into a URL - open it anywhere, the editor loads it.
- **Undo/redo** with Ctrl+Z and Ctrl+Shift+Z, **Delete** or **Backspace**
removes the selection, **Ctrl+D** duplicates it, **Ctrl+C / Ctrl+X /
Ctrl+V** copy, cut and paste it (also into another design or tab),
**Alt+↑** selects the parent, **Escape** the view, **Ctrl+S** saves the
design. In the outline the arrow keys walk the tree.
design is also kept in the browser between visits (when the browser
refuses to keep it, the editor says so; when another tab of the editor
saves over it, too, with a button to load that one). *Save in browser*
keeps it there under its class name, next to others; *Designs in this
browser* lists those, and what New, Open or Import replaced. **Copy share
link** puts the whole design into a URL - open it anywhere, the editor
loads it (a link of more than 8 kB says so: some chats and mail cut it).
- **Undo/redo** with Ctrl+Z and Ctrl+Shift+Z - each step brings back the
control that was selected. **Delete** or **Backspace** removes the
selection, **Ctrl+D** duplicates it, **Ctrl+↑ / Ctrl+↓** move it among
its siblings, **Ctrl+C / Ctrl+X / Ctrl+V** copy, cut and paste it (also
into another design or tab), **Alt+↑** selects the parent, **Escape**
the view, **Ctrl+S** saves the design. In the outline the arrow keys walk
the tree and a letter jumps to the next control of that name; in the
control search Enter inserts the first match; the tabs of the drawer go
by arrow key too. **?** lists every shortcut.
- **Several controls at once**: Ctrl+click (or Shift+click) on the canvas,
in the outline or in the code adds a control to the selection. Delete,
duplicate, move, copy and cut act on all of them; *Wrap in…* puts
controls side by side into a new VBox, HBox, FlexBox or Panel. Selected
rows of the outline drag together.
- A **right-click** on a control - on the canvas or in the outline, or
Shift+F10 - opens its context menu: move, copy, cut, paste, duplicate,
wrap, delete, and *Copy properties* / *Paste properties*, which set the
properties of one control on others that have them.
- A **double-click** on a control on the canvas edits its text right
there (text, title, header text, …): Enter keeps it, Escape takes it
back.
- *Controls* lists the controls inserted last first, under *Recently
used*. An empty container gets room and a dashed frame on the canvas, so
there is something to drop into.
- The **outline filter** shows the controls whose type or text matches, and
the way down to them.
- A drop on the canvas lands before, into or after the control under the
pointer: the upper quarter is before, the lower after. The panels on the
left and right can be dragged wider.
- **Checks** lists what would break the class or the view, and inputs
whose entry goes nowhere.
whose entry goes nowhere. A click on a line selects the control and
focuses the property it is about; where there is one fix, a button does
it: create the attribute a binding names, remove an unused one, reset a
value UI5 would refuse, build the template of a bound list, bind an input
to a new attribute.
- **Properties** show the default of the canvas's UI5 where nothing is
set, and an event field offers the names the design raises already - two
buttons, one `WHEN` branch.
- **Data**: attributes and fields move up and down (their order is the
order of the declarations), and *Paste rows…* takes sample rows copied
from a spreadsheet or CSV - with a header line, the columns go to the
fields of the same name, and a new name becomes a new field.
- **Preview** mode lists the events the view raised, with what the user
had changed in the model by then - what `on_event` would read.
- The editor itself is light, dark or as the system (◐ in the bar at the
top); the canvas keeps the UI5 theme chosen for it. The canvas zooms out
to 75% or 50% for a large view at a glance - the device width stays the
width the view gets.
- The outline marks controls bound to data (●) and controls that raise an
event (⚡); *Copy* above the code copies what the tab shows.
- The canvas can show a phone or tablet width, the Horizon, Quartz or
Belize themes, and any UI5 version. Enter `1.71.80` to see the view on the
oldest release abap2UI5 supports.
Expand Down Expand Up @@ -246,9 +292,10 @@ runtime. Run it when the palette gains a control.
| `src/model.js` | The design document and every edit on it |
| `src/abap.js` | Design → the ABAP class and its abapGit files |
| `src/xml.js` | Design → XML view (preview, export), and XML view → design (import) |
| `src/diff.js` | The line diff of the *Changes* tab |
| `src/app.js` | The editor UI: wires the panels and renders them on every change |
| `src/ui/store.js` | The state, commit( ) with undo and the browser store, selection |
| `src/ui/*.js` | One module per panel: insert, layers, inspector, data, code, preview, palette, files, keys, edit (drop and clipboard) |
| `src/ui/*.js` | One module per panel: insert, layers, inspector, data, code, preview, palette, files, keys, edit (drop and clipboard), actions (the edits on the selection, for keys, palette, canvas toolbar and context menu), context (the context menu), inline (a text edited on the canvas) |
| `src/preview/init.js` | The preview frame (a UI5 module) |
| `tools/` | Dev server, metadata dump, class generation, runtime verification |
| `test/` | Unit tests, fixtures, the builder model, browser tests |
Expand Down
17 changes: 15 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@
<button id="btnNew" role="menuitem">New from template…</button>
<button id="btnOpen" role="menuitem">Open design (.json)…</button>
<button id="btnSave" role="menuitem" title="Ctrl+S">Save design (.json)</button>
<button id="btnSaveBrowser" role="menuitem" title="Keep the design in this browser, under its class name">Save in browser</button>
<button id="btnOpenClass" role="menuitem" title="An abap2UI5 app class - its view, data and events become the design, the rest of the class is kept">Open ABAP class…</button>
<button id="btnImport" role="menuitem">Import UI5 XML view…</button>
<button id="btnRecent" role="menuitem">Recent designs…</button>
<button id="btnRecent" role="menuitem" title="The designs saved in this browser, and those New, Open or Import replaced">Designs in this browser…</button>
</div>
</div>
<button id="btnTheme" class="ghost icon" title="Appearance of the editor: as the system" aria-label="Appearance of the editor">◐</button>
<button id="btnUndo" class="ghost icon" title="Undo (Ctrl+Z)" aria-label="Undo">↶</button>
<button id="btnRedo" class="ghost icon" title="Redo (Ctrl+Shift+Z)" aria-label="Redo">↷</button>
<div class="menu-wrap split">
Expand Down Expand Up @@ -70,7 +72,10 @@
<div id="insertList" class="scroll"></div>
</section>
<section class="panel hidden" id="panel-layers" role="tabpanel">
<div id="layers" class="scroll tree" role="tree" aria-label="Outline"></div>
<div class="panel-head">
<input id="layersFilter" type="search" placeholder="Filter the outline" aria-label="Filter the outline">
</div>
<div id="layers" class="scroll tree" role="tree" aria-label="Outline" aria-multiselectable="true"></div>
</section>
<section class="panel hidden" id="panel-data" role="tabpanel">
<div id="dataPanel" class="scroll pad"></div>
Expand Down Expand Up @@ -98,6 +103,11 @@
<button data-device="820px" title="Tablet">Tablet</button>
<button data-device="390px" title="Phone">Phone</button>
</div>
<select id="zoom" aria-label="Zoom of the canvas" title="Zoom of the canvas - a large view at a glance">
<option value="1">100%</option>
<option value="0.75">75%</option>
<option value="0.5">50%</option>
</select>
<select id="theme" aria-label="Theme">
<option value="sap_horizon">Horizon</option>
<option value="sap_fiori_3">Quartz Light</option>
Expand All @@ -112,14 +122,17 @@
<div class="device-frame" id="deviceFrame">
<iframe id="preview" title="Preview"></iframe>
</div>
<div id="eventLog" class="event-log hidden" aria-live="polite" aria-label="Events of the preview"></div>
</div>
<div class="code-pane" id="codePane">
<div class="code-head">
<div class="seg small" role="group" aria-label="Code">
<button data-code="abap" class="active">ABAP class</button>
<button data-code="xml">XML view</button>
<button data-code="diff" id="btnDiff" hidden title="What the export changes in the class as it was opened">Changes</button>
</div>
<span id="codeInfo" class="muted"></span>
<button id="btnCopyCode" class="ghost small" title="Copy what this tab shows">Copy</button>
</div>
<pre id="code" class="codeblock" tabindex="0" aria-label="Generated code"></pre>
</div>
Expand Down
3 changes: 3 additions & 0 deletions preview.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#content { height: 100%; }
.dsg-hover { outline: 1px dashed #0064d9 !important; outline-offset: -1px; }
.dsg-sel { outline: 2px solid #0064d9 !important; outline-offset: -2px; }
.dsg-empty { min-height: 2.75rem !important; min-width: 5rem; box-sizing: border-box; outline: 1px dashed #8396a8; outline-offset: -1px;
background: repeating-linear-gradient(-45deg, transparent 0 6px, rgba(131, 150, 168, 0.08) 6px 12px) !important; }
.dsg-also { outline: 2px solid #0064d9 !important; outline-offset: -2px; background-color: rgba(0, 100, 217, 0.05) !important; }
.dsg-drop { outline: 2px dashed #0064d9 !important; outline-offset: -2px; background-color: rgba(0, 100, 217, 0.06) !important; }
.dsg-drop-before { box-shadow: 0 -3px 0 0 #0064d9 !important; }
.dsg-drop-after { box-shadow: 0 3px 0 0 #0064d9 !important; }
Expand Down
Loading
Loading