views

webclient grammar version zora.rc5.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' {
						'path': component 'query context path'
					}
					'root' { [ root ] }
				)
				'path': [ path ] component 'query path'
			}
			'candidates' { [ candidates of ]
				'path': component 'query context path'
				'property': [ reference: ] reference
			}
		)
		'filters': group {
			'todo filter': stategroup (
				'yes' { [ where has-todo ]
					'path': [ (, ) ] component 'node path'
					'users filter': stategroup (
						'requesting user' { [ for user ] }
						'none' { }
					)
				}
				'no' { }
			)
			'filters': dictionary { [ where ]
				'type': [ : ] stategroup (
					'property' {
						'path': component 'node path'
						'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' {
						'path': component 'node path'
						'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
							}
						)
					}
					'texts' {
						'value': text
						'operator': stategroup (
							'in' { [ in ] }
							'not in' { [ not in ] }
						)
						'text paths': [ (, ) ] set {
							'path': [ - ] component 'node path'
							'property': [ . ] 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'
		}
	)
}
'query context path' {
	'start at': stategroup (
		'root' { [ @root ] }
		'view context' {
			'ancestor path': component 'ancestor node path'
		}
	)
	'steps': component 'gui node type path step'
}
'ancestor node path' {
	'has steps': stategroup (
		'no' { }
		'yes' { [ ^ ]
			'tail': component 'ancestor node path'
		}
	)
}
'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
				}
				'query filter' { [ query ]
					'type': stategroup (
						'text' { [ text ] }
						'generic' { }
					)
					'filter': [ filter ] reference
				}
				'query collection filter' {
					'filter': [ query collection filter ] 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' { }
		)
		'enumerable': stategroup (
			'no' { [ no-enum ] }
			'yes' { }
		)
		'hidden': stategroup (
			'no' { }
			'yes' { [ hidden ] }
		)
		'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'
			}
		)
	}
}

If no-enum is provided, the query property will be excluded from the columns collection in the client bindings. For exmaple: it is only available as a query text or query text column binding.

'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
			'type': stategroup (
				'candidates' { [ candidates ] }
				'existing entries' { }
			)
			'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
		}
	)
}