Writing Actions in TypeScript
When you have created your own custom projection, this projection is exactly that:
a projection. Other than the built-in default behavior (held in the file
~/picode/editor/<yourLanguageName>DefaultActions.ts
), there are no actions defined yet.
Actions are necessary to enable the user to change the model and add elements to it.
The projections only describe what you will see in the editor.
Actions determine what you can do, how you interact with the editor.
As a convenience, the file ~/picode/editor/Custom<yourLanguageName>Actions.ts
is generated, which is a placeholder
for your own actions written in TypeScript. This file contains four constants for
different kind of actions. What you need to
do is to define these constants. Then Freon will merge your actions
with the default actions. If a trigger for an action is identical to a default one,
your custom actions take precedence.
export const MANUAL_EXPRESSION_CREATORS: PiExpressionCreator[] = [
// Add your own custom expression creators here
];
export const MANUAL_BINARY_EXPRESSION_CREATORS: PiBinaryExpressionCreator[] = [
// Add your own custom binary expression creators here
];
export const MANUAL_CUSTOM_BEHAVIORS: PiCustomBehavior[] = [
// Add your own custom behavior here
];
export const MANUAL_KEYBOARD: KeyboardShortcutBehavior[] = [
// Add your own custom keyboard shortcuts here
];
Creation of New Elements
Now, let’s start with adding an element, e.g. adding a new property
to an
Entity
.
From Actions you will have learned
that an AliasBox
is a predefined box where the user can type text to trigger some action.
Thus, we add an AliasBox
to the projection of the property list.
Note the role of the box: end-of-property-list.
// tutorial-language/editor/CustomEntityProjection.ts#L141-L146
new VerticalListBox(entity,"attributes",
entity.attributes.map(att => {
return this.getBox(att);
})
).addChild(new AliasBox(entity, "end-of-attribute-list",
"add attribute"))
Then we create the actual action and attach it to the role of the AliasBox
. Note that the projection
and action
are defined in two different files, respectively CustomEntityProjections.ts
and CustomEntityActions.ts
.
// tutorial-language/editor/CustomEntityActions.ts#L40-L51
{
activeInBoxRoles: ["end-of-attribute-list"], // <1>
trigger: "attribute", // <2>
action: (box: Box, trigger: PiTriggerType, editor: PiEditor): PiElement | null => { // <3>
var entity: Entity = box.element as Entity;
const attribute: AttributeWithLimitedType = new AttributeWithLimitedType();
entity.attributes.push(attribute);
return attribute;
},
boxRoleToSelect: "Attribute-name" // <4>
},
];
The numbers in the comments indicate what happens here:
- The action is attached to each box with the role “end-of-property-list”.
- The action will be triggered when the user types
"attribute"
inside theAliasBox
. - The executable code for the action. It creates a new
AttributeWithLimitedType
and attaches is toentity
- The focus of the editor is returned to the
Box
with the role"Attribute-name"
within the entity. This ensures that the user can immediately start typing the name of the entity after it has been created.
There can be many boxes with the same role in the editor, as long as their model element is different. This way, the above action is available for each attribute list in each entity.
Custom Actions
// TODO document other custom actions
Expressions and Binary Expressions
// TODO Advanced expression editing.
Keyboard Shortcuts
// TODO A keyboard shortcut specifies an action that is triggered by special keys, like e.g. Ctrl-A.