widget

webclient grammar version seven.5.0

'binding context': stategroup (
	'none' { [ static ] }
	'select' {
		'binding': [ binding ] reference
		'switch client binding context': stategroup (
			'yes' { [ on ]
				'constrained on containing binding': stategroup (
					'yes' {
						'type path': component 'client binding type path'
						'instance binding': reference
					}
					'no' { [ unconstrained ]
						'instance binding': reference
					}
				)
			}
			'no' { }
		)
	}
)
'widget': component 'widget configuration node'
'expression': component 'expression'
'client binding type path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'type': stategroup (
				'state' {
					'state group': [ ? ] reference
					'state': [ * ] reference
				}
				'collection' {
					'collection': [ . ] reference
				}
				'binding' {
					'instance binding': reference
				}
			)
			'tail': component 'client binding type path'
		}
	)
}
'configuration attribute persistence' {
	'persist': stategroup (
		'yes' { [ @persist ]
			'per session': stategroup (
				'yes' { [ session ] }
				'no' { }
			)
			'per entry': stategroup (
				'yes' { [ entry ] }
				'no' { }
			)
		}
		'no' { }
	)
}
'optional state HACK' { }
'widget configuration node' { [ {, } ]
	'attributes': dictionary {
		'switch client binding context': stategroup (
			'yes' { [ on ]
				'constrained on containing binding': stategroup (
					'yes' {
						'type path': component 'client binding type path'
					}
					'no' { [ unconstrained ]
						'instance binding': reference
					}
				)
			}
			'no' { }
		)
		'type': [ : ] stategroup (
			'widget' {
				'lazy': stategroup (
					'yes' { [ lazy widget ] }
					'no' { [ widget ] }
				)
			}
			'window' { [ window ]
				'node': component 'widget configuration node'
			}
			'view' { [ view ] }
			'inline view' { [ inline view ] }
			'configuration' { [ configuration ]
				'type': stategroup (
					'number' { [ number ] dynamic-order
						'persistence': component 'configuration attribute persistence'
						'has default': stategroup (
							'yes' { [ default: ]
								'value': integer
							}
							'no' { }
						)
					}
					'text' { [ text ] dynamic-order
						'has default': stategroup (
							'yes' { [ default: ]
								'value': text
							}
							'no' { }
						)
						'persistence': component 'configuration attribute persistence'
					}
					'list' { [ list ]
						'node': component 'widget configuration node'
					}
					'state group' { [ stategroup ] dynamic-order
						'has default': stategroup (
							'yes' { [ default: ]
								'state': reference
							}
							'no' { }
						)
						'persistence': component 'configuration attribute persistence'
						'states': [ (, ) ] dictionary {
							'state default': component 'optional state HACK'
							'node': [ -> ] component 'widget configuration node'
						}
					}
				)
			}
			'binding' { [ binding ]
				'constrained on containing binding': stategroup (
					'yes' {
						'type path': component 'client binding type path'
						'instance binding': reference
					}
					'no' { [ unconstrained ]
						'instance binding': reference
					}
				)
				'node': component 'widget configuration node'
			}
		)
	}
}

A widget can be initialized ‘lazily’. The engine will not create subscriptions or initialize queries for the widget if the widget is not rendered in the widget implementation.

'widget implementation context parent path' {
	'has parent step': stategroup (
		'no' { }
		'yes' { [ ^ ]
			'tail': component 'widget implementation context parent path'
		}
		'root' { [ root ] }
	)
}
'control binding' {
	'binding type': stategroup (
		'let declaration' {
			'path': [ @ ] component 'widget implementation context parent path'
			'on widget implementation node': stategroup (
				'yes' {
					'declaration': reference
				}
			)
		}
		'static' {
			'control': [ control ] reference
			'node binding': component 'widget implementation node'
		}
		'window' {
			'window': [ window ] reference
			'control binding': component 'control binding'
		}
		'widget' {
			'context': component 'context selection'
			'widget': [ widget ] reference
		}
		'client binding widget' {
			'context': [ binding widget ] component 'context selection'
		}
		'inline view' { [ inline view ]
			'context': component 'context selection'
			'view': reference
		}
	)
}
'entries list' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'node binding': component 'widget implementation node'
			'tail': component 'entries list'
		}
	)
}
'context selection' {
	'change context to': stategroup (
		'engine state' { [ engine ]
			'engine state binding': reference
		}
		'other context' {
			'parent path': component 'widget implementation context parent path'
			'path': component 'context selection path'
		}
	)
}
'bound context selection' {
	'context': component 'context selection'
	'cast': stategroup (
		'to binding' { [ $ ] }
	)
}
'context selection path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'type': stategroup (
				'unconstrained configuration attribute' {
					'configuration attribute': [ unconstrained :: ] reference
				}
				'constrained configuration attribute' {
					'configuration attribute': [ :: ] reference
				}
				'client binding' {
					'binding': [ switch to ] reference
				}
			)
			'tail': component 'context selection path'
		}
	)
}
'instruction selection' {
	'configuration attribute type': stategroup (
		'binding' {
			'context': component 'bound context selection'
			'instruction': [ >> ] reference
			'has arguments': stategroup (
				'no' { }
				'yes' {
					'first argument': [ (, ) ] component 'instruction argument'
				}
			)
		}
		'collection' {
			'type': stategroup (
				'configuration' {
					'context': component 'context selection'
					'list': [ = ] reference
					'instruction selection': component 'instruction selection'
				}
				'binding' {
					'context': component 'bound context selection'
					'collection property': [ . ] reference
					'instruction selection': component 'instruction selection'
				}
			)
		}
		'switch' {
			'switch': component 'expression'
		}
		'ignore' { [ ignore ] }
		'configuration' {
			'context': component 'context selection'
			'instruction': stategroup (
				'set state' { [ set state ]
					'state group': reference
					'state': [ : ] reference
					'node': component 'instruction argument configuration node'
				}
				'set number' { [ set number ]
					'number': reference
					'argument': [ = ] component 'number argument'
				}
				'set text' { [ set text ]
					'text': reference
					'argument': [ = ] component 'text argument'
				}
			)
		}
	)
}
'instruction argument' {
	'type': stategroup (
		'number' { [ number ]
			'argument': component 'number argument'
		}
		'text' { [ text ]
			'argument': component 'text argument'
		}
		'file' { [ file ] }
		'view' { [ view ]
			'context': component 'context selection'
			'view configuration': reference
		}
	)
	'next argument': stategroup (
		'no' { }
		'exists' { [ , ]
			'argument': component 'instruction argument'
		}
	)
}
'instruction argument configuration node' { [ (, ) ]
	'attributes': dictionary {
		'type': stategroup (
			'configuration' {
				'type': [ : ] stategroup (
					'number' { [ number ]
						'argument': [ = ] component 'number argument'
					}
					'text' { [ text ]
						'argument': [ = ] component 'text argument'
					}
					'state group' { [ state ]
						'state': reference
						'node': component 'instruction argument configuration node'
					}
				)
			}
		)
	}
}
'instruction list' {
	'instruction selection': component 'instruction selection'
	'has steps': stategroup (
		'no' { }
		'yes' { [ , ]
			'tail': component 'instruction list'
		}
	)
}
'widget implementation attribute' {
	'expression': [ : ] component 'expression'
}
'widget implementation node' { [ {, } ]
	'define context': stategroup (
		'yes' { [ define context ]
			'context': component 'context selection'
			'let declarations': dictionary { [ let ]
				'expression': [ : ] component 'expression'
			}
		}
		'no' { }
	)
	'attributes': dictionary {
		'attribute': component 'widget implementation attribute'
	}
}
'expression' {
	'type': stategroup (
		'attribute' {
			'control attribute type': stategroup (
				'instruction' { [ instruction ]
					'type': stategroup (
						'singular' {
							'instruction': component 'instruction selection'
						}
						'list' {
							'instruction list': [ [, ] ] component 'instruction list'
						}
					)
				}
				'markup' { [ markup ]
					'control binding': component 'control binding'
				}
				'control' { [ control ]
					'implementation': component 'widget implementation node'
				}
				'property' {
					'type': stategroup (
						'dictionary' { [ collection ]
							'binding type': stategroup (
								'empty' { [ empty ] }
								'widget binding' {
									'context': component 'bound context selection'
									'collection property': [ . ] reference
									'sort': component 'expression'
									'node binding': component 'widget implementation node'
								}
							)
						}
						'list' { [ list ]
							'binding type': stategroup (
								'static' {
									'entries': [ [, ] ] component 'entries list'
								}
								'configuration' {
									'context': component 'context selection'
									'list': [ = ] reference
									'node binding': component 'widget implementation node'
								}
								'widget binding' {
									'context': component 'bound context selection'
									'collection property': [ . ] reference
									'sort': component 'expression'
									'node binding': component 'widget implementation node'
								}
							)
						}
						'number' { [ number ]
							'number binding': component 'number binding'
						}
						'text' { [ text ]
							'type': stategroup (
								'binding' {
									'text binding': component 'text binding'
								}
								'concatenation' {
									'strings': [ [, ] ] component 'string list'
								}
							)
						}
						'state group' { [ state ]
							'state': reference
							'binding': component 'widget implementation node'
						}
					)
				}
			)
		}
		'control' {
			'control binding': component 'control binding'
		}
		'any' { [ any ]
			'from': stategroup (
				'collection' {
					'context': component 'bound context selection'
					'collection': [ . ] reference
					'key': [ [, ] ] component 'text binding'
				}
				'list' {
					'context': component 'context selection'
					'list': [ . ] reference
					'index': [ [, ] ] component 'number binding'
				}
			)
			'cases': [ (, ) ] group {
				'true': [ | true -> ] component 'expression'
				'false': [ | false -> ] component 'expression'
			}
		}
		'switch' {
			'type': stategroup (
				'configuration' {
					'context': component 'context selection'
					'state group': [ ? ] reference
					'states': [ (, ) ] dictionary { [ | ]
						'next': [ -> ] component 'expression'
					}
				}
				'binding' {
					'context': component 'bound context selection'
					'property': [ ? ] reference
					'states': [ (, ) ] dictionary { [ | ]
						'next': [ -> ] component 'expression'
					}
				}
			)
		}
		'match' { [ match ]
			'type': stategroup (
				'text' { [ text ]
					'left expression': component 'text binding'
					'right expression': [ == ] component 'text binding'
				}
				'number' { [ number ]
					'left expression': component 'number binding'
					'right expression': [ == ] component 'number binding'
				}
			)
			'cases': [ (, ) ] group {
				'true': [ | true -> ] component 'expression'
				'false': [ | false -> ] component 'expression'
			}
		}
		'sort collection' {
			'by': stategroup (
				'value' { [ sort by ]
					'context': component 'bound context selection'
					'direction': stategroup (
						'ascending' { [ ascending ] }
						'descending' { [ descending ] }
					)
				}
				'none' { }
			)
		}
	)
}
'number argument' {
	'type': stategroup (
		'control number' { [ argument ]
			'transform': stategroup (
				'no' { }
				'yes' { [ transform ]
					'transformer': [ # ] reference
				}
			)
		}
		'control text' { [ argument ]
			'transformer': [ transform ] reference
		}
		'binding' {
			'number binding': component 'number binding'
		}
	)
}
'text argument' {
	'type': stategroup (
		'control text' { [ argument ] }
		'binding' {
			'key': component 'text binding'
		}
	)
}
'number binding' {
	'binding type': stategroup (
		'static number' {
			'value': integer
		}
		'current time' { [ current time ]
			'throttle': stategroup (
				'yes' {
					'interval': [ interval: ] integer
				}
				'no' { }
			)
		}
		'configuration' {
			'context': component 'context selection'
			'bound number': [ = ] reference
		}
		'widget binding' {
			'context': component 'bound context selection'
			'property': [ # ] reference
		}
		'list index' {
			'context': [, index ] component 'context selection'
		}
	)
	'transform': stategroup (
		'no' { }
		'yes' { [ transform ]
			'transformer': reference
		}
	)
}
'text binding' {
	'binding type': stategroup (
		'static' {
			'text': text
		}
		'phrase' {
			'phrase': [ phrase ] reference
		}
		'configuration' {
			'context': component 'context selection'
			'type': stategroup (
				'text' {
					'bound text': [ = ] reference
					'format': stategroup (
						'no' { }
						'yes' { [ format ]
							'formatter': reference
						}
					)
				}
				'number' {
					'number': [ configuration # ] reference
					'format': stategroup (
						'no' { }
						'yes' { [ format ]
							'formatter': reference
						}
					)
				}
			)
		}
		'widget binding' {
			'context': component 'bound context selection'
			'type': stategroup (
				'text' {
					'type': stategroup (
						'key' { [ .key ] }
						'reference' { [ > ]
							'property': reference
						}
						'text' { [ : ]
							'property': reference
						}
					)
					'format': stategroup (
						'no' { }
						'yes' { [ format ]
							'formatter': reference
						}
					)
				}
				'number' { [ # ]
					'property': reference
					'format': stategroup (
						'no' { }
						'yes' { [ format ]
							'formatter': reference
						}
					)
				}
			)
		}
	)
}
'string list' {
	'text binding': component 'text binding'
	'has steps': stategroup (
		'no' { }
		'yes' { [ , ]
			'tail': component 'string list'
		}
	)
}