Fonto Why & How: My button is disabled?! Attributes in operations

Fonto Why & How: My button is disabled?! Attributes in operations

In this weekly series Martin describes a question that was raised by a Fonto developer, how it was resolved and why Fonto behaved like that in the first place. This week we are covering Stencils. Stencils are one of the oldest APIs in Fonto. While they are very powerful, they can be very unwieldy. In this post I want to highlight a common question: why does Fonto not let me insert an element with a required attribute!

A support question came up with the following question: I want to insert a <link /> element with the href attribute set to whatever a user chose from a modal. But the button for it is disabled. What is happening?

Let’s take a look at the code. This is the operation:

{
	":insert-xref": {
		"label": "t__Hyperlink",
		"description": "t__Insert a link to a web address.",
		"icon": "globe",
		"steps": [
			{
				"type": "operation/open-web-reference-modal-for-insert"
			},
			{
				"type": "operation/insert-inline-frame-element",
				"data": {
					"nodeName": "link",
					"attributes": {
						"href": "{{url}}"
					}
				}
			}
		]
	}
}

The operation is used in an FXOperationButton like this:

<FxOperationButton operationName=":insert-xref" />

The schema says the following about this <link /> element:

$ fdt element link
  fdt element <element>  
  Looking up schemas... (27ms)
  Reading from my-sx-shell  
  Found 1 element definitions for element "link" across 703 elements.  

  Definition 1  
    Element name   link
    Namespace URI  http://www.example.com/
    Documentation  -
    Contents       Text and elements (mixed)
    Contained by   166 unique nodes (23.6%)
    Contains       98 unique nodes (13.9%)
    Attributes     30 unique attributes
    Default class  -

    Contained by  
    ... <omitted for brevity> ...

    Attributes  
    class, href*, role, ... <omitted for brevity> ...  

We see that the <link /> element’s href attribute has an asterisk at the end. That means it is required: the element is not valid to the schema if the attribute is not there. But looking back to the operation, the attribute is always going to be there, right? It will be filled from the modal! Except when the operation is computed for it’s state: the modal will not show up, resulting in the (theoretical) insertion if a link without an href set. Which is not allowed: the schema disallows that.

The fix is easy: just make sure to always provide a stub value for the href. We commonly do this by setting ‘initialData’:

{
	":insert-xref": {
		"label": "t__Hyperlink",
		"description": "t__Insert a link to a web address.",
		"icon": "globe",
		"initialData": {
			"url": "stub-value"
		},
		"steps": [
			{
				"type": "operation/open-web-reference-modal-for-insert"
			},
			{
				"type": "operation/insert-inline-frame-element",
				"data": {
					"nodeName": "link",
					"attributes": {
						"href": "{{url}}"
					}
				}
			}
		]
	}
}

This works! The button is enabled and we can click on it!

Why though

We fixed the bug: the button for adding a link element is enabled. But why did this matter? We should look at our operations pipeline. Operations are the building blocks of interactions with Fonto. They are behind just about every button, they hande just about every shortcut and they even handle text input. They open modals, close sidebars and change XML. They can be active (usually visualized by having a button pressed in), enabled (aka allowed, clickable) or disabled (aka disallowed, unavailable). This state of an operation is called OperationState and computed by dry-running an operation.

We perform a dry-run of an operation to determine its state. For operations that change the XML structure, we actually change the XML structure! But in a sandbox. For the operation that inserts a link, we actually insert a link at the place of the selection and check its validity according to the schema. More on this sandboxing structure in a future blogpost!

Not all operation steps can sensibly be performed in a sandbox. For example modals cannot be sandboxed. Getting the state of a modal changes nothing on the operation data, resulting in the href to be set to undefined. This undefined is synonymous to having the attribute absent in JSONML. Which causes the operation to insert a link without an href to be inserted (in the sandbox). By setting the initialData.url property to a stubbed value, the href will be set to that instead. Causing the operation to work in the getState flow as well.

I hope this explained how Fonto works and why it works like that. During the years we have built quite the product and we are aware some parts work in unexpected ways for those who have not been with it from the start. If you have any points of Fonto you would like some focus on, we are always ready and willing to share! Reach out on Twitter to Martin Middel (@dr_rataplan) or file a support issue!

Stay up-to-dateFonto Why & How posts direct in your inbox

Receive updates on new Fonto Why & How blog posts by email

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top