ΞΆ

Getting started

First control

All controls are created through control factory `new zeta.UI()`.
// create control factory var ui = new zeta.UI(); // define a button named "demoButton" var button = ui.button('demoButton'); // render the button in the space on the right // and context object is returned by render method var context = button.render(div);

Name vs label

Although label for a control is automatically set to the control's name if not given, the recommended way to specify labels is either explicitly set on control's options or through `ui.i18n()`. Examples on this page only use labels directly for brevity.
var ui = new zeta.UI(); var buttonlist = ui.buttonlist( // directly use label as name ui.checkbox('Demo Checkbox'), // recommended way #1 ui.checkbox('demoCheckbox'), // recommended way #2 ui.checkbox('anotherCbx', { label: 'Demo Checkbox' }) ); // recommended way #1 ui.i18n('en', 'demoCheckbox', 'Demo Checkbox'); // you will see why directly use label as name is not a good idea // as just changing the label would break you code! var context = buttonlist.render(div); console.log(context.toJSON()); // click to inspect =[context]

Icon

Most button-like controls support icons. Currently only Material icons are supported. For a complete list of icons please see https://material.io/tools/icons.
var ui = new zeta.UI(); var button = ui.button('Done', { icon: 'done' }); button.render(div);

Action

Actions can be assigned to any controls by the `execute` option. Actions are triggered either by user interactions, e.g. mouse click, for button-like controls or when value is changed for controls that let user to input values to or choose values from.
var ui = new zeta.UI(); var button = ui.button('Click me', { execute: function () { console.log('Button clicked'); } }); button.render(div);

Lifecycle

Init and destroy

var ui = new zeta.UI(); var button = ui.button({ label: 'Click me to remove', execute: function (self) { // remove clicked button from button list self.destroy(); }, init: function (e, self) { console.log(self.name + ':', 'init'); }, destroy: function (e, self) { console.log(self.name + ':', 'destroy'); } }) var buttonlist = ui.buttonlist( ui.button('Add button', function (self) { self.parent.append(button); }), // append 3 buttons initially button, button, button ); buttonlist.render(div);

Property change and DOM update

var ui = new zeta.UI(); var buttonset = ui.buttonset( ui.checkbox({ // templated value will also be re-evaluated and upon changes to other properties // and is included in propertyChange event if the evaluated string differs from previous value label: 'Value is {{value}}', propertyChange: function (e) { console.log('Old values:', e.oldValues); console.log('New values:', e.newValues); }, // stateChange event is fired whenever updates to DOM are needed // such as changes to control states (enabled, active, ...) or // property changed, or focus entering or leaving the control stateChange: function (e) { console.log('DOM update') } }) ); buttonset.render(div);

Async operation

Any control that returns a promise when execution will be automatically locked to prevent double execution. The `pending` flag of that control will be on during the period, and the `asyncStart` and `asyncEnd` event fired.
var ui = new zeta.UI(); var button = ui.button('Click me', { execute: function () { console.log('Do async stuff. Now clicking the button again will not execute again until async end'); return delay(5000); }, asyncStart: function (e, self) { console.log('Async operation started. self.pending =', self.pending); }, asyncEnd: function (e, self) { console.log('Async operation ended. self.pending =', self.pending); } }); button.render(div);

Scripting with control

Finding controls

Controls can be retrieved either through control's `all` property or through the context object.
var ui = new zeta.UI(); var buttonset = ui.buttonset(ui.checkbox(), ui.textbox(), { init: function (e, self) { // within control event // console.log(self.all); } }); var context = buttonset.render(div); // get from context object // click to inspect =[ui.all(context)] // alternatively get from DOM element // click to inspect =[ui.all(div)]

Control state

var ui = new zeta.UI(); var buttonset = ui.buttonlist( ui.button('Enabled', { enabled: function () { return true; } }), ui.button('Disabled', { enabled: function () { return false; } }), ui.button('Active', { active: function () { return true; } }), ui.button('Hidden', { visible: function () { return false; } }), ui.button('Disabled', { hiddenWhenDisabled: true, enabled: function () { return false; } }) ); buttonset.render(div);

Setting control state

Alternatively the three control states can be set during runtime.
var ui = new zeta.UI(); var buttonset = ui.buttonlist( ui.button('Enabled', { init: function (e, self) { self.enabled = true; } }), ui.button('Disabled', { init: function (e, self) { self.enabled = false; } }), ui.button('Active', { init: function (e, self) { self.active = true; } }), ui.button('Hidden', { init: function (e, self) { self.visible = false; } }) ); buttonset.render(div);

Control dependency

var ui = new zeta.UI(); var buttonset = ui.buttonset( ui.checkbox('toggle'), ui.button('demoButton', 'favorite', { init: function (e, self) { self.all.toggle.on('stateChange', function (e, checkbox) { self.enabled = checkbox.value; }); } }) ); buttonset.render(div);

Context object

Two-way bindings

By default two-way bindings are created on the context object for controls that has a value.
var ui = new zeta.UI(); var buttonset = ui.buttonset(ui.checkbox(), ui.textbox()); var context = buttonset.render(div); // try setting values to context object // or inspect context object after playing controls context.checkbox = true; // click to inspect =[context] // the same object that can retrieve by other components // click to run =[zeta.dom.getContext(div)]

Action bindings

By default any non-valued control that can be executed, like a button that has the `execute` option defined, method are created on the context object that executes the control. For other types of control there may also be method created to do other stuff. See individual control types for more information.
var ui = new zeta.UI(); var button = ui.button('demoButton', function (self) { console.log('Button clicked'); }); var context = button.render(div); // click to run =[context.demoButton()]

Custom bindings

Bindings with custom logic can be done via a get/setter.
var ui = new zeta.UI(); var button = ui.button({ init: function (e, self) { zeta.helper.defineGetterProperty(self.context, 'icon', function () { return self.icon; }, function (value) { self.icon = value; }); } }); var context = button.render(div); context.icon = 'favorite';

Using contextChange event

The contextChange event is an interface where external code can actively notify about changes that does not simply reflect on simple value change.
var ui = new zeta.UI(); var dropdown = ui.dropdown({ contextChange: function (e, self) { // event fired when context.update() is called self.choices = self.context.choices; } }); var context = dropdown.render(div); context.choices = ['One', 'Two', 'Three']; context.update();

Modularization

Import and export control

var ui = new zeta.UI(); ui.export('custom.namespace', ui.button('Button 1'), ui.button('Button 2') ); var anotherUI = new zeta.UI(); var buttonlist = anotherUI.buttonlist( anotherUI.import('custom.namespace') ); buttonlist.render(div);

Labels in separate file

It is common to put language resources in a separate file. Those labels can be imported without accessing control factory by a namespace.
// label.en.js // add labels to the "example" namespace zeta.UI.i18n('example', 'en', { 'demoButton': 'Demo Button' }); // main.js // use labels in the "example" namespace var ui = new zeta.UI('example'); ui.button('demoButton').render(div);

Advanced usage

Observing custom property

var ui = new zeta.UI(); var button = ui.button({ init: function (e, self) { self.watch('customProperty', function (newValue, oldValue) { console.log('customProperty changed from', oldValue, 'to', newValue); }); }, propertyChange: function (e) { // custom property is included in propertyChange event when observed console.log(e.newValues); }, execute: function (self) { self.customProperty = true; } }); button.render(div);

Control ordering

var ui = new zeta.UI(); var buttonlist = ui.buttonlist( ui.button('Last button', { after: '*' }), ui.button('Button') ); buttonlist.render(div);

Keyboard and mouse event

var ui = new zeta.UI(); var textbox = ui.textbox({ click: function (e) { console.log('Mouse clicked'); }, enter: function (e) { console.log('Key pressed:', e.eventName); }, keystroke: function (e) { console.log('Key pressed:', e.data); } }); textbox.render(div);

Realm

Controls can be assigned to different realms to identify which contexts those controls required. It looks for the named property on the toolset state object `self.state` and if the value is a falsy one (e.g. `0`, `false`, `null`, ...), that control will be disabled. Controls disabled by this way is in the sense that it is truly disabled rather than in a disabled state. No events nor the `enabled` method will be called.
var ui = new zeta.UI('realm', { contextChange: function (e, self) { console.log('realm:', self.foo ? 'enabled' : 'disabled'); } }); var buttonset = ui.buttonset( // toggle flag and trigger contextChange event ui.button('Toggle', function (self) { self.state.foo = !self.state.foo; self.context.update(); }, { showText: true }), // only show and enable when foo is true ui.dropdown('Foo', { realm: 'foo', choices: ['One', 'Two', 'Three'], contextChange: function () { console.log('dropdown: contextChange event fired'); }, enabled: function () { console.log('dropdown: enabled method called') return true; } }) ); buttonset.render(div);

Templated label

Templated value can be used for observed properties. Consult the wiki for waterpipe for template syntax.
var ui = new zeta.UI(); var button = ui.button('Click me', function (self) { // increment count by each click self.count = (self.count || 0) + 1; // display how many clicks in button label self.label = 'Clicked {{count}} times'; // which is also reflected in control's property console.log(self.label); }); button.render(div);

Customizing outlook

var ui = new zeta.UI(); var dropdown = ui.dropdown({ template: '<div><div class="title">{{label}}</div><z:dropdown/></div>', label: 'Test Dropdown', choices: ['One', 'Two', 'Three'] }); dropdown.render(div);

Button

Simple button

var ui = new zeta.UI(); var button = ui.button('Click me', function () { console.log('Button clicked'); }); button.render(div);

Danger button

var ui = new zeta.UI(); var button = ui.button('Danger', { danger: true }); button.render(div);

Simulate click

var ui = new zeta.UI(); var button = ui.button('demoButton', function (self) { console.log('Button clicked'); }); var context = button.render(div); // execute method is exposed to context object // same as clicked by user // click to execute =[context.demoButton()]

Hyperlink button

Link with icon

var ui = new zeta.UI(); var link = ui.link({ icon: 'open_in_new', label: 'GitHub Homepage', value: 'https://github.com/misonou/jquery-typer', target: '_blank' }); link.render(div);

Menu

Show menu

var ui = new zeta.UI(); var menu = ui.menu( ui.button('Menu item 1'), ui.button('Menu item 2'), ui.button('Menu item 3') ).render(/* notice that no arguments are given here */); var $link = $('<a href="javascript:void 0;">Show menu</a>'); $link.click(function () { menu.showMenu(this); }); $link.appendTo(div);

Context menu

var ui = new zeta.UI(); var menu = ui.menu( ui.button('Menu item 1'), ui.button('Menu item 2'), ui.button('Menu item 3') ).render(/* notice that no arguments are given here */); zeta.dom.on(div, 'rightClick', function (e) { menu.showMenu({ x: e.clientX, y: e.clientY }); e.preventDefault(); }); div.appendChild(document.createTextNode('Right click in region here'));

Menu button

Simple menu button

var ui = new zeta.UI(); var callout = ui.callout('Menu', ui.button('Menu item 1'), ui.button('Menu item 2'), ui.button('Menu item 3') ); callout.render(div);

Grouping menu items

var ui = new zeta.UI(); var callout = ui.callout('Menu', // separator will be displayed for nested button list ui.buttonlist( ui.button('Menu item 1'), ui.button('Menu item 2') ), ui.button('Menu item 3') ); callout.render(div);

Toolbar in menu

var ui = new zeta.UI(); var callout = ui.callout('Menu', // buttonlist required to show the separator ui.buttonlist( ui.buttonset( ui.button('button1', 'favorite'), ui.button('button1', 'lock') ) ), ui.button('Menu item 1'), ui.button('Menu item 2'), ui.button('Menu item 3') ); callout.render(div);

Item description

var ui = new zeta.UI(); var callout = ui.callout('Menu', ui.button('Menu item 1', { description: 'Description 1' }), ui.button('Menu item 2', { description: 'Description 2' }), ui.button('Menu item 3', { description: 'Description 3' }) ); callout.render(div);

Command shortcut

var ui = new zeta.UI(); var callout = ui.callout('Menu', ui.button('Menu item 1', { // command shortcut is automatically resolved // when command name is supplied execute: 'dummy_command' }), ui.button('Menu item 2', { // or manually provide shortcut: 'ctrlAltQ' }) ); zeta.dom.setShortcut('dummy_command', 'ctrlAltP'); callout.render(div);

Button mode

var ui = new zeta.UI(); var callout = ui.callout('Menu', 'menu', ui.button('Disable me', 'favorite', { init: function (e, self) { self.enabled = false; }, execute: function (self) { // since only one button is enabled after disabling // callout will become like a normal button self.enabled = false; console.log('Enter button mode'); } }), ui.button('Button', 'lock_open', { execute: function (self) { self.all['Disable me'].enabled = true; console.log('Enter menu mode'); } }), // specifies callout to become button when needed { alwaysShowCallout: false } ); callout.render(div);

Toolbar

Simple toolbar

var ui = new zeta.UI(); var buttonset = ui.buttonset( ui.button('button1', 'search'), ui.button('button2', 'favorite'), ui.button('button3', 'lock') ); buttonset.render(div);

Hiding button label

var ui = new zeta.UI(); var buttonset = ui.buttonset( ui.button('button1', 'search'), ui.button('button2', 'favorite'), ui.button('button3', 'lock'), { showText: false } ); buttonset.render(div);

Input fields

Dropdown

Simple dropdown

var ui = new zeta.UI(); var dropdown = ui.dropdown('Dropdown', ['One', 'Two', 'Three'], function (self) { console.log(self.value); }); dropdown.render(div);

Initial value

var ui = new zeta.UI(); var dropdown = ui.dropdown('Dropdown', ['One', 'Two', 'Three'], 'One'); dropdown.render(div);

Non-empty

var ui = new zeta.UI(); var dropdown = ui.dropdown('Dropdown', ['One', 'Two', 'Three'], { allowEmpty: false }); dropdown.render(div);

Using map for choices

// use zeta.shim.Map for support in IE 10 var choices = new zeta.shim.Map(); choices.set(1, 'One'); choices.set(2, 'Two'); choices.set(3, 'Three'); var ui = new zeta.UI(); var dropdown = ui.dropdown('Dropdown', choices, function (self) { // value will be the key added to the map console.log(self.value); }); dropdown.render(div);

Fixed label

var ui = new zeta.UI(); var dropdown = ui.dropdown('Dropdown', { valueAsLabel: false, choices: ['One', 'Two', 'Three'] }); dropdown.render(div);

Additional menu item

var ui = new zeta.UI(); var dropdown = ui.dropdown('Dropdown', { value: 'One', choices: ['One', 'Two', 'Three'], controls: [ // buttonlist required to show line // between choices and the additional item ui.buttonlist( ui.button('Additional button', function () { console.log('Button clicked'); }), // show the addition item after choices { after: '*' } ) ], execute: function () { console.log('Dropdown changed'); } }); dropdown.render(div);

Checkbox

Simple checkbox

var ui = new zeta.UI(); var checkbox = ui.checkbox('Checkbox', function (self) { console.log(self.value); }); checkbox.render(div);

Required

var ui = new zeta.UI(); var checkbox = ui.checkbox('Checkbox', { required: true }); checkbox.render(div);

Textbox

Simple textbox

var ui = new zeta.UI(); var textbox = ui.textbox(); textbox.render(div);

Required

var ui = new zeta.UI(); var textbox = ui.textbox({ required: true }); textbox.render(div);

Multiline textarea

var ui = new zeta.UI(); var textbox = ui.textbox({ options: { lineBreak: true } }); textbox.render(div);

Maximum length

var ui = new zeta.UI(); var textbox = ui.textbox('input', { options: { validation: { maxlength: 6 } } }); var context = textbox.render(div); context.input = '012345678';

Character blacklist

var ui = new zeta.UI(); var textbox = ui.textbox('input', { options: { validation: { invalidChars: '~"#%&*:<>?/\{|}' } } }); var context = textbox.render(div); context.input = '0123&456?';

Character whitelist

var ui = new zeta.UI(); var textbox = ui.textbox('input', { options: { validation: { allowChars: '~"#%&*:<>?/\{|}' } } }); var context = textbox.render(div); context.input = '0123&456?';

Keep label

var ui = new zeta.UI(); var textbox = ui.textbox('input', { showPlaceholder: 'always' }); var context = textbox.render(div); context.input = '0123&456?';

Custom placeholder

var ui = new zeta.UI(); var textbox = ui.textbox('input', { placeholder: 'This is placeholder. This is a very long description.' }); var context = textbox.render(div);

Number

Simple number input

var ui = new zeta.UI(); var textbox = ui.number(); textbox.render(div);

Min/max

var ui = new zeta.UI(); var textbox = ui.number({ options: { min: 0, max: 10 } }); textbox.render(div);

Step

var ui = new zeta.UI(); var textbox = ui.number({ options: { step: 10 } }); textbox.render(div);

Loop

var ui = new zeta.UI(); var textbox = ui.number({ options: { min: 1, max: 5, loop: true } }); textbox.render(div);

Tags

Simple tag input

var ui = new zeta.UI(); var textbox = ui.keyword({ execute: function (self) { console.log(self.value); } }); textbox.render(div);

Suggestions

var ui = new zeta.UI(); var textbox = ui.keyword({ options: { allowedValues: 'ice,tongue,fate,mild,homosexual,dividend,throw,chief,drop,spokesperson,distort,sensitivity,fault,despair,moment,soft,short circuit,bottom,referee,chew'.split(',') }, execute: function (self) { console.log(self.value); } }); textbox.render(div);

Suggestions label/icon

var ui = new zeta.UI(); var textbox = ui.keyword({ options: { allowedValues: [ { value: '1', label: 'One', icon: 'looks_one' }, { value: '2', label: 'Two', icon: 'looks_two' }, { value: '3', label: 'Three', icon: 'looks_3' } ] }, execute: function (self) { console.log(self.value); } }); textbox.render(div);

Defined values only

var ui = new zeta.UI(); var textbox = ui.keyword('tags', { options: { allowFreeInput: false, allowedValues: ['One', 'Two', 'Three'] } }); var context = textbox.render(div); context.tags = ['Four'];

Date picker

Date picker

var ui = new zeta.UI(); var datepicker = ui.datepicker(); datepicker.render(div);

Week picker

var ui = new zeta.UI(); var datepicker = ui.datepicker({ options: { mode: 'week' }, execute: function () { console.log(this.value); } }); datepicker.render(div);

Month picker

var ui = new zeta.UI(); var datepicker = ui.datepicker({ options: { mode: 'month' }, execute: function () { console.log(this.value); } }); datepicker.render(div);

Date/time picker

var ui = new zeta.UI(); var datepicker = ui.datepicker({ options: { mode: 'datetime' }, execute: function () { console.log(this.value); } }); datepicker.render(div);

Min/max date

var ui = new zeta.UI(); var datepicker = ui.datepicker({ options: { min: 'today', max: '+14day' }, execute: function () { console.log(this.value); } }); datepicker.render(div);

Calendar

var ui = new zeta.UI(); var calendar = ui.calendar({ execute: function () { console.log(this.value); } }); calendar.render(div);

File upload

Multiple file upload

var ui = new zeta.UI(); var file = ui.file('Upload', 'file_upload', { multiple: true, execute: function (self) { console.log(self.value); } }); file.render(div);

Rich text editor

Sample editor

var ui = new zeta.UI(); var rte = ui.richtext(); rte.render(div);

Dialog

Alert box

var ui = new zeta.UI(); var button = ui.button('Click me', function () { ui.alert('This is an alert box').then(function (value) { console.log(value); }); }); button.render(div); // alternatively you can create alert box without factory // click to run =[zeta.UI.alert('This is an alert box')]

Confirm box

var ui = new zeta.UI(); var button = ui.button('Click me', function () { ui.confirm('This is an confirm box').then(function (value) { console.log(value); }); }); button.render(div); // alternatively you can create alert box without factory // click to run =[zeta.UI.confirm('This is an confirm box')]

Prompt box

var ui = new zeta.UI(); var button = ui.button('Click me', function (self) { ui.prompt('This is an prompt box', 'Initial value').then(function (value) { console.log(value); }); }); button.render(div); // alternatively you can create alert box without factory // click to run =[zeta.UI.prompt('This is an prompt box')]

Using label as message

var ui = new zeta.UI(); ui.i18n('en', 'alertMessage', 'This is an alert box'); var button = ui.button('Click me', function () { ui.alert('alertMessage'); }); button.render(div);

Custom dialog

var ui = new zeta.UI(); var dialog = ui.dialog( ui.checkbox({ required: true }), ui.buttonset( ui.submit('submit', 'done'), ui.button('cancel', 'cancel', function (self) { // close the dialog without executing return self.all.dialog.destroy(); }) ) ); var button = ui.button('Click me', function () { // notice that no arguments are given to render() var context = dialog.render(); context.dialog.then(function (value) { // do stuff like submitting request to server console.log('Submitted', value); }, function () { console.log('Cancelled') }); }); button.render(div);

Dialog with async operation

var ui = new zeta.UI(); var dialog = ui.dialog( ui.textbox(), ui.checkbox(), ui.buttonset( ui.submit('submit', 'done') ), { execute: function (self) { return delay(5000); } }); var button = ui.button('Click me', function () { // notice that no arguments are given to render() var context = dialog.render(); context.dialog.then(function (value) { console.log('Submitted', value); }, function () { console.log('Cancelled') }); }); button.render(div);

Title and description

var ui = new zeta.UI(); var dialog = ui.dialog( ui.textbox(), ui.buttonset( ui.submit('submit', 'done') ), { title: 'This is title', description: 'This is description.' }); var button = ui.button('Click me', function () { dialog.render(); }); button.render(div);

Error message

var ui = new zeta.UI(); var dialog = ui.dialog( ui.textbox(), ui.buttonset( ui.submit('submit', 'done') ), { execute: function (self) { return zeta.helper.reject('Error occured'); } }); var button = ui.button('Click me', function () { dialog.render(); }); button.render(div);

Danger zone

var ui = new zeta.UI(); var dialog = ui.dialog( ui.checkbox(), ui.buttonset( ui.submit('submit', 'done'), ui.button('delete', 'delete', { // put this button in danger zone danger: true, execute: function (self) { console.log('Danger button clicked'); return self.all.dialog.destroy(); } }) ) ); var button = ui.button('Click me', function () { dialog.render().dialog.then(function (value) { console.log('Submitted', value); }, function () { console.log('Cancelled') }); }); button.render(div);

Form

Simple form

var ui = new zeta.UI(); var form = ui.form( ui.textbox('value'), ui.buttonset( ui.submit('Submit', 'done') ), { execute: function () { // do stuff like submitting request to server console.log('Send to server', this.context.toJSON()); return delay(5000, { result: 'OK' }); } }); form.render(div);

Initial values

Although initial values can be supplied as individual `value` option for each control, it is recommended to supplied it through `render()` method to increase reusability.
var ui = new zeta.UI(); var form = ui.form( ui.textbox('value'), ui.buttonset( ui.submit('Submit', 'done') ) ); form.render(div, { value: 'Initial value' });

Validation

var ui = new zeta.UI(); var form = ui.form( ui.textbox('value', { required: true }), ui.buttonset( ui.submit('Submit', 'done') ), function () { // will not execute if textbox is empty console.log('Form executed'); } ); form.render(div);

Resetting form fields

var ui = new zeta.UI(); var form = ui.form( ui.fieldset('Field set', ui.textbox('Textbox 1'), ui.textbox('Textbox 2'), ui.checkbox('Checkbox'), { description: 'Try playing with form fields and then click Reset.' } ), ui.buttonset( ui.button('Reset', 'undo', function (self) { self.context.reset(); }) ) ); form.render(div, { 'Textbox 1': 'foo', 'Checkbox': true });

Form section

var ui = new zeta.UI(); var form = ui.form( ui.fieldset('Normal section', ui.textbox('Textbox 1'), ui.textbox('Textbox 2') ), ui.fieldset('Optional section', ui.textbox('value', { required: true }), { optional: true, description: 'This is an optional set. When ' } ), ui.buttonset( ui.submit('Submit', 'done') ), function (self) { console.log('Validation passed') } ); var context = form.render(div); // try playing with the fields and form sections and inspect the values // click to inspect =[context.toJSON()]