views

webclient grammar version yar.11.0

'dependencies': dictionary { [ using ] }
'views': dictionary {
	'translate title': stategroup (
		'no' { }
		'yes' {
			'title': [ as ] reference
		}
	)
	'node type': [ (, ) ] component 'gui node type path'
	'queries': dictionary { [ query ]
		'context': [ from ] stategroup (
			'node' {
				'switch': stategroup (
					'current' {
						'query context': component 'gui node type path step'
					}
					'root' { [ root ] }
				)
				'path': [ path ] component 'query path'
			}
			'candidates' { [ candidates of ]
				'property context': component 'gui node type path step'
				'property': [ reference: ] reference
			}
		)
		'filters': group {
			'todo filter': stategroup (
				'yes' { [ where has-todo ]
					'path': [ (, ) ] component 'node path'
				}
				'no' { }
			)
			'filters': dictionary {
				'path': [ : ] component 'node path'
				'type': stategroup (
					'property' {
						'property': [ . ] reference
						'type': stategroup (
							'number' {
								'expression': component 'number filter expression'
							}
							'state group' { [ in ]
								'states to include': [ (, ) ] dictionary { [ ? ] }
							}
							'text' { [ = ]
								'text': text
							}
							'collection' {
								'operator': stategroup (
									'in' { [ in ] }
									'not in' { [ not in ] }
								)
								'keys': [ (, ) ] dictionary { [ [, ] ] }
							}
						)
					}
					'node' {
						'type': stategroup (
							'existence' {
								'operator': stategroup (
									'exists' { [ exists ] }
									'not exists' { [ not exists ] }
								)
							}
							'view context' { [ = view context ] }
							'containment' {
								'operator': stategroup (
									'in' { [ in ] }
									'not in' { [ not in ] }
								)
								'references': reference
							}
						)
					}
				)
			}
		}
		'query limits': [ limit: ] group {
			'sample': stategroup (
				'yes' {
					'sample size': integer
					'show all limit': [ /, / ] integer
				}
				'no' { }
			)
			'absolute maximum': integer
		}
		'properties': component 'node query'
	}
	'instance': component 'widget expression'
}

The view context is the location in the model where the view binds to. This is especially convenient for queries that filter on the current node.

'gui node type path step' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'attribute': [ . ] reference
			'type': stategroup (
				'state' {
					'state': [ ? ] reference
				}
				'node' { }
			)
			'tail': component 'gui node type path step'
		}
	)
}
'gui node type path' {
	'steps': component 'gui node type path step'
}
'widget configuration list' {
	'expression': component 'widget expression'
	'has next': stategroup (
		'no' { }
		'yes' { [ , ]
			'next': component 'widget configuration list'
		}
	)
}
'view context parent path' {
	'type': stategroup (
		'state parent' { [ ?^ ] }
		'collection parent' { [ .^ ] }
		'group parent' { [ +^ ] }
	)
	'has tail': stategroup (
		'no' { }
		'yes' {
			'tail': component 'view context parent path'
		}
	)
}
'view context path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'type': stategroup (
				'query entry' { [ entry ] }
				'parent' {
					'path': component 'view context parent path'
				}
				'reference' { [ > ] }
				'entity' { [ $ ] }
				'state rule' { [ .& ] }
			)
		}
	)
}
'widget expression' {
	'type': stategroup (
		'switch' {
			'path': component 'node path'
			'state group': [ switch ] reference
			'states': [ (, ) ] dictionary { [ | ]
				'next': [ => ] component 'widget expression'
			}
		}
		'produce value' {
			'value': component 'widget expression tail'
		}
	)
}
'widget expression tail' {
	'type': stategroup (
		'default' { [ default ] }
		'widget' { [ widget ]
			'path': component 'context path'
			'type': stategroup (
				'inline' {
					'lazy': stategroup (
						'no' { }
						'yes' { [ lazy ] }
					)
					'widget': reference
					'configuration': component 'widget expression tail'
				}
				'view' { [ view ]
					'using views': stategroup (
						'internal' { }
						'external' { [ from ]
							'views': reference
						}
					)
					'view': [ : ] reference
				}
			)
		}
		'window' {
			'window': [ window ] reference
			'configuration': component 'widget expression tail'
		}
		'view' {
			'render': stategroup (
				'in window' { [ open view ]
					'window': [ @ ] reference
				}
			)
			'using views': stategroup (
				'internal' { }
				'external' { [ from ]
					'views': reference
				}
			)
			'view context': component 'view context path'
			'view': [ : ] reference
		}
		'number' {
			'source': stategroup (
				'now' { [ now ]
					'has offset': stategroup (
						'none' { }
						'yes' {
							'offset': [ + ] integer
						}
					)
				}
				'static' {
					'number': integer
				}
			)
		}
		'text' {
			'type': stategroup (
				'static' {
					'value': text
				}
				'phrase' {
					'value': reference
				}
				'key' {
					'path': component 'context path'
					'translate': [ key ] stategroup (
						'yes' { [ phrase ] }
						'no' { }
					)
				}
			)
		}
		'list' {
			'empty': stategroup (
				'yes' { [ empty ] }
				'no' {
					'path': component 'context path'
					'list': [ => [, ] ] component 'widget configuration list'
				}
			)
		}
		'states list' {
			'path': component 'context path'
			'has states': stategroup = node-switch .'states' (
				| nodes = 'yes' { 'first' = first }
				| none  = 'no'
			)
			'states': [ states (, ) ] dictionary {
				'has successor': stategroup = node-switch successor (
					| node = 'yes' { 'successor' = successor }
					| none = 'no'
				)
				'expression': [ = ] component 'widget expression'
			}
		}
		'state group' {
			'state': [ create ] reference
			'configuration': component 'widget expression tail'
		}
		'node' { [ (, ) ]
			'configuration': dictionary {
				'expression': [ = ] component 'widget expression'
			}
		}
		'binding' { [ :: ]
			'type': stategroup (
				'window' { [ window ]
					'window': reference
				}
				'entity' { [ entity ] }
				'node' { [, node ]
					'path': component 'node path'
				}
				'user' { [ user ] }
				'collection' { [ collection ]
					'path': component 'context path'
					'collection': reference
					'join': stategroup (
						'yes' { [ join ] }
						'no' { }
					)
				}
				'joined entry' { [ join ] }
				'ordered graph' { [ ordered-graph ]
					'ordered graph': [ : ] reference
				}
				'sort property' { [ sort ]
					'on': stategroup (
						'text' { [ text ] }
						'number' { [ number ] }
						'state group' { [ stategroup ] }
					)
					'property path': component 'node path'
					'property': reference
				}
				'query' { [ query ]
					'path': component 'context path'
					'query context': stategroup (
						'node' {
							'query': reference
						}
						'candidates' { [ candidates ]
							'query': reference
						}
					)
					'has refresh interval': stategroup (
						'no' { }
						'yes' { [ refresh: ]
							'interval': integer
						}
					)
				}
				'group' { [ group ]
					'path': component 'context path'
					'group': reference
				}
				'state group' { [ stategroup ]
					'path': component 'context path'
					'state group': reference
				}
				'state' { [ state ]
					'state group context': stategroup (
						'states list' { }
						'state group binding' {
							'state': reference
						}
					)
				}
				'state rule' {
					'path': component 'context path'
					'rule': [ state rule ] reference
				}
				'property rule' { [ rule ]
					'rule': reference
				}
				'number' { [ number ]
					'path': component 'context path'
					'property': reference
				}
				'text' { [ text ]
					'path': component 'context path'
					'property': reference
				}
				'file' { [ file ]
					'path': component 'context path'
					'property': reference
				}
				'command' { [ command ]
					'path': component 'context path'
					'command': reference
				}
				'action' { [ action ]
					'path': component 'context path'
					'action': reference
					'can use containing view': stategroup (
						'no' { }
						'yes' { [ use containing view ] }
					)
					'view bindings': dictionary {
						'window': [ : open view @ ] reference
						'using views': stategroup (
							'internal' { }
							'external' { [ from ]
								'views': reference
							}
						)
						'view': [ : ] reference
						'can open entry': stategroup (
							'no' { }
							'yes' {
								'window': [ and open view @ ] reference
								'using views': stategroup (
									'internal' { }
									'external' { [ from ]
										'views': reference
									}
								)
								'view': [ : ] reference
							}
						)
					}
				}
				'query number' {
					'number': [ query number ] reference
				}
				'query text' {
					'text': [ query text ] reference
				}
				'query file' {
					'file': [ query file ] reference
				}
				'query stategroup' {
					'stategroup': [ query stategroup ] reference
				}
				'query collection' {
					'collection': [ query collection ] reference
				}
				'report' {
					'path': component 'context path'
					'report': [ report ] reference
				}
				'report text parameter' {
					'text': [ report text ] reference
				}
				'report number parameter' {
					'number': [ report number ] reference
				}
			)
			'configuration': component 'widget expression tail'
		}
		'none' { [ none ] }
	)
}
'node step' {
	'type': stategroup (
		'parent' { [ ^ ] }
		'state rule' { [ .& ]
			'rule': reference
		}
		'reference rule' {
			'property': [ . ] reference
			'rule': [ & ] reference
		}
		'reference' {
			'text': [ > ] reference
		}
		'group' {
			'group': [ . ] reference
		}
		'collection entry' {
			'collection': [ . ] reference
			'entry key': [ [, ] ] text
		}
		'state' {
			'state group': [ . ] reference
			'state': [ ? ] reference
		}
	)
}
'context path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'step': component 'node step'
			'tail': component 'context path'
		}
	)
}
'node path' {
	'path': component 'context path'
}
'node query' {
	'has properties': stategroup = node-switch .'properties' (
		| nodes = 'yes' { 'first' = first }
		| none  = 'no'
	)
	'properties': [ [, ] ] dictionary {
		'has successor': stategroup = node-switch successor (
			| node = 'yes' { 'successor' = successor }
			| none = 'no'
		)
		'name': reference
		'column type': stategroup (
			'id' { [ id ] }
			'content' { }
		)
		'path': [ -> ] component 'node path'
		'type': [ : ] stategroup (
			'text' {
				'text': [ text ] reference
				'filter': stategroup (
					'none' { }
					'simple' { [ filter ]
						'criteria': text
					}
					'current id path' { [ filter ] }
					'containment' {
						'operator': stategroup (
							'in' { [ in ] }
							'not in' { [ not in ] }
						)
						'references': reference
					}
				)
			}
			'file' { [ file ]
				'file': reference
			}
			'number' {
				'number': [ number ] reference
				'has filter': stategroup (
					'no' { }
					'yes' { [ filter ]
						'operator selected': stategroup (
							'no' { }
							'yes' {
								'operator': stategroup (
									'smaller than' { [ < ] }
									'smaller than or equal to' { [ <= ] }
									'equal to' { [ = ] }
									'greater than or equal to' { [ >= ] }
									'greater than' { [ > ] }
								)
							}
						)
						'initial criteria': stategroup (
							'none' { [ none ] }
							'yes' {
								'source': stategroup (
									'now' { [ now ]
										'has offset': stategroup (
											'none' { }
											'yes' {
												'offset': [ + ] integer
											}
										)
									}
									'static' {
										'number': integer //fixme nest criteria in operator selected
									}
								)
							}
						)
					}
				)
			}
			'state group' {
				'state group': [ stategroup ] reference
				'has filter': stategroup (
					'no' { }
					'yes' { [ filter ]
						'filter enabled': stategroup (
							'yes' { [ enabled ] }
							'no' { [ disabled ] }
						)
						'states': [ ? ] dictionary { [ | ]
							'is selected': stategroup (
								'no' { }
								'yes' { [ selected ] }
							)
						}
					}
				)
			}
			'collection' {
				'collection': [ collection ] reference
				'has filter': stategroup (
					'no' { }
					'yes' { [ filter ]
						'operator': stategroup (
							'in' { [ in ] }
							'not in' { [ not in ] }
						)
						'keys': dictionary { [ (, ) ] }
					}
				)
				'properties': component 'node query'
			}
			'widget' {
				'instance': component 'widget expression'
			}
		)
	}
}
'query path step' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'type': stategroup (
				'group' {
					// The '+' is used to be compatibel with the client request schema.
					'group': [ + ] reference //FIXME use dot notation
				}
				'state' {
					'state group': [ . ] reference
					'state': [ ? ] reference
				}
			)
			'tail': component 'query path step'
		}
	)
}
'query path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'head': component 'query path step'
			'collection': [ . ] reference
			'tail': component 'query path'
		}
	)
}
'number filter expression' {
	'operator': stategroup (
		'range' {
			'greater than': stategroup (
				'yes' { [ > ]
					'criterium': integer
				}
				'no' { }
			)
			'less than': stategroup (
				'yes' { [ < ]
					'criterium': integer
				}
				'no' { }
			)
		}
		'equals' { [ == ]
			'criterium': integer
		}
	)
}