Durchsuchbare Dokumentation aufrufen | Zurück zur Dokumentationsübersicht
Navigation: Dokumentationen agorum core > agorum core für Entwickler > agorum core aguila
Das agorum.tabContainer-Layout stellt jedes seiner Elemente in einem eigenen Reiter dar. Das System verwendet das title-Attribut des Elements als Überschrift des Reiters.
Hinweis: Das System blendet die Reiter für die mit hidden unsichtbar markierten Elemente zwar aus, Sie können Sie aber immer noch programmatisch aktivieren. Sorgen Sie dafür, dass jederzeit nur sichtbare Registerkarten aktiv sind.
Hinweis: Änderungen an der Registerkarten-Struktur (Hinzufügen oder Entfernen von Tabs) erfolgen über das Neuzuweisen des Parameters items.
Löst aus, wenn das System programmatisch oder ein Benutzer den aktiven Reiter ändert.
Das System übergibt als Parameter den neuen Wert des Parameters activeTab.
Löst aus, sobald ein Benutzer eine Tab-Überschrift mit der linken Maustaste anklickt.
Das System übergibt als Parameter den Index des angeklickten Reiters.
Hinweis: Das Event löst bei jedem Klick auf eine Tab-Überschrift aus, unabhängig davon, ob der Reiter bereits aktiv war. Für reine Wechsel-Reaktionen ist stattdessen activeTabChanged vorgesehen.
Löst aus, sobald ein Benutzer eine Tab-Überschrift mit der rechten Maustaste anklickt.
Das System übergibt als Parameter den Index des angeklickten Reiters.
Löst aus, sobald ein Benutzer eine Tab-Überschrift mit der mittleren Maustaste anklickt.
Das System übergibt als Parameter den Index des angeklickten Reiters.
Löst aus, sobald ein Benutzer eine Tab-Überschrift mit der linken Maustaste doppelt anklickt.
Das System übergibt als Parameter den Index des angeklickten Reiters.
Enthält den Index des aktiven Tabs.
Sie können den Index sowohl lesen als auch setzen.
Definiert das zu verwendende Symbol für das Widget (siehe Liste von aguila-icons).
Hinweis: Um Symbole für einzelne Tab-Überschriften zu setzen, verwenden Sie den Parameter icon am jeweiligen Kind-Widget (also z. B. an der vbox, die als Tab dient).
keine
Dieses Beispiel stellt zwei einfache Formulare in zwei getrennten Reitern dar: im ersten Tab ein Textfeld mit Schaltfläche, im zweiten Tab ein einzelnes Eingabefeld.
/* Basic example for the agorum.tabContainer widget.
* Shows two tabs with different content and demonstrates:
* - How to define the title of each tab via the `title` property of the child widget.
* - How to observe the currently active tab via the `activeTabChanged` event.
* - How to programmatically switch tabs via the `activeTab` property.
*/
let aguila = require('common/aguila');
let tabContainer = aguila.create({
type: 'agorum.tabContainer',
name: 'basicTabContainer',
width: 400,
height: 300,
activeTab: 0,
items: [
{
type: 'agorum.vbox',
title: 'Tab 1',
name: 'tab1',
items: [
{
type: 'agorum.composite.form.element.text',
name: 'greetingInput',
label: 'Greeting',
value: 'Hello, world!',
flexible: true,
},
{
type: 'agorum.hbox',
items: [
{ type: 'agorum.spacer', flexible: true },
{
type: 'agorum.button',
name: 'switchToSecondTabButton',
text: 'Switch to Tab 2',
},
],
},
],
},
{
type: 'agorum.vbox',
title: 'Tab 2',
name: 'tab2',
items: [
{
type: 'agorum.composite.form.element.text',
name: 'inputField',
label: 'Your input',
value: 'Hello, world!',
},
{
type: 'agorum.composite.form.element.text',
name: 'activeTabStatus',
label: 'Active tab index',
readOnly: true,
value: 'Active tab index: 0',
},
],
},
],
});
/* React to any tab change - programmatic or user-triggered. */
let activeTabStatus = tabContainer.down('activeTabStatus');
tabContainer.on('activeTabChanged', newIndex => {
activeTabStatus.value = 'Active tab index: ' + newIndex;
});
/* Programmatically switch to the second tab. */
tabContainer.down('switchToSecondTabButton').on('clicked', () => {
tabContainer.activeTab = 1;
});
tabContainer;
Das folgende Beispiel registriert alle vier Klick-Events auf einem tabContainer. Jeder Klick auf eine Tab-Überschrift wird in der Konsole ausgegeben, inklusive Index des angeklickten Tabs.
/* Demonstrates the four new tab click events of agorum.tabContainer:
* - tabClicked - fires when a user clicks a tab header with the left mouse button.
* - tabRightClicked - fires when a user clicks a tab header with the right mouse button.
* - tabMiddleClicked - fires when a user clicks a tab header with the middle mouse button.
* - tabDblClicked - fires when a user double-clicks a tab header with the left mouse button.
*
* Each event delivers an integer parameter with the index of the clicked tab header.
*
*/
let aguila = require('common/aguila');
let TAB_CLICK_EVENTS = ['tabClicked', 'tabRightClicked', 'tabMiddleClicked', 'tabDblClicked'];
let tabContainer = aguila.create({
type: 'agorum.tabContainer',
name: 'tabClickEventsContainer',
width: 600,
height: 420,
items: [
{
type: 'agorum.vbox',
title: 'Tab 1',
name: 'tab1',
items: [
{
type: 'agorum.composite.form.element.text',
name: 'tab1Hint',
label: 'Hint',
readOnly: true,
value: 'Left click, right click, middle click or double click any tab header.',
},
],
},
{
type: 'agorum.vbox',
title: 'Tab 2',
name: 'tab2',
items: [
{
type: 'agorum.composite.form.element.text',
name: 'tab2Hint',
label: 'Hint',
readOnly: true,
value: 'Every click type is reported below - even on the currently active tab.',
},
],
},
{
type: 'agorum.vbox',
title: 'Tab 3',
name: 'tab3',
items: [
{
type: 'agorum.composite.form.element.text',
name: 'eventLog',
label: 'Event log',
readOnly: true,
textArea: true,
monospace: true,
flexible: true,
value: '',
},
{
type: 'agorum.hbox',
items: [
{ type: 'agorum.spacer', flexible: true },
{
type: 'agorum.button',
name: 'clearLogButton',
text: 'Clear log',
},
],
},
],
},
],
});
let eventLog = tabContainer.down('eventLog');
/**
* Append a new line to the event log inside the third tab.
*
* @param {string} message Message to append
*/
let appendToLog = message => {
let previous = eventLog.value || '';
eventLog.value = previous + (previous ? '\n' : '') + message;
};
/* Register all four new tab click events in the same way. */
TAB_CLICK_EVENTS.forEach(eventName => {
tabContainer.on(eventName, tabIndex => {
let title = (tabContainer.items[tabIndex] && tabContainer.items[tabIndex].title) || '(unknown)';
let message = eventName + ' -> index=' + tabIndex + ', title=' + title;
console.log(message);
appendToLog(message);
});
});
/* Also log the classic activeTabChanged event for comparison. */
tabContainer.on('activeTabChanged', newIndex => {
appendToLog('activeTabChanged -> index=' + newIndex);
});
tabContainer.down('clearLogButton').on('clicked', () => {
eventLog.value = '';
});
tabContainer;
Ein typischer Anwendungsfall des Events tabMiddleClicked ist das Schließen von Reitern, analog zu den bekannten Reitern in Webbrowsern. Das folgende Beispiel entfernt das angeklickte Tab und hält dabei den Index des aktiven Tabs konsistent.
/* Practical example: close tabs via middle mouse click (as known from web browsers).
*
* Demonstrates:
* - Using the new tabMiddleClicked event to detect a middle click on a tab header.
* - Removing the clicked tab by reassigning the `items` array of agorum.tabContainer
* (mutation is not allowed; see aguila widget guidelines).
* - Keeping the `activeTab` index valid after the removal.
* - Re-adding new tabs dynamically to show that middle-click closes only the target tab.
*/
let aguila = require('common/aguila');
let dynamicTabCounter = 3;
/**
* Build a fresh tab definition with a short instruction inside.
*
* @param {string} title Title shown on the tab header
* @param {string} name Unique widget name of the tab content
* @param {string} hint Hint text displayed inside the tab
*/
let buildTab = (title, name, hint) => ({
type: 'agorum.vbox',
title: title,
name: name,
items: [
{
type: 'agorum.composite.form.element.text',
name: name + 'Hint',
label: 'Hint',
readOnly: true,
value: hint,
},
],
});
let tabContainer = aguila.create({
type: 'agorum.tabContainer',
name: 'closableTabContainer',
width: 520,
height: 320,
items: [
buildTab('Tab 1', 'tab1', 'Middle-click any tab header to close it.'),
buildTab('Tab 2', 'tab2', 'Middle-click any tab header to close it.'),
buildTab('Tab 3', 'tab3', 'Middle-click any tab header to close it.'),
],
});
/**
* Remove the tab at the given index and adjust the active tab if needed.
* The items array is reassigned - never mutated - to comply with the aguila
* widget guidelines.
*
* @param {number} indexToRemove Index of the tab to close
*/
let closeTab = indexToRemove => {
let existingItems = tabContainer.items || [];
if (indexToRemove < 0 || indexToRemove >= existingItems.length) {
return;
}
let updatedItems = existingItems.slice(0, indexToRemove).concat(existingItems.slice(indexToRemove + 1));
tabContainer.items = updatedItems;
/* Keep activeTab pointing to a still-existing tab. */
if (updatedItems.length === 0) {
return;
}
if (tabContainer.activeTab >= indexToRemove && tabContainer.activeTab > 0) {
tabContainer.activeTab = tabContainer.activeTab - 1;
}
};
tabContainer.on('tabMiddleClicked', tabIndex => {
closeTab(tabIndex);
});
/* Extra: allow re-adding tabs to demonstrate that closing works reliably. */
let addTabToolbar = aguila.create({
type: 'agorum.hbox',
items: [
{
type: 'agorum.button',
name: 'addTabButton',
text: 'Add a new tab',
},
{ type: 'agorum.spacer', flexible: true },
{
type: 'agorum.composite.form.element.text',
name: 'closeHint',
readOnly: true,
value: 'Tip: middle-click a header to close it.',
},
],
});
let widget = aguila.create({
type: 'agorum.vbox',
name: 'closableTabExample',
width: 520,
height: 360,
items: [addTabToolbar, tabContainer],
});
widget.down('addTabButton').on('clicked', () => {
dynamicTabCounter = dynamicTabCounter + 1;
let newTabName = 'tab' + dynamicTabCounter;
let existingItems = tabContainer.items || [];
tabContainer.items = existingItems.concat([
buildTab('Tab ' + dynamicTabCounter, newTabName, 'Middle-click any tab header to close it.'),
]);
tabContainer.activeTab = tabContainer.items.length - 1;
});
widget;
Das Event tabRightClicked eignet sich, um eine kontextbezogene Aktion für einen bestimmten Reiter anzubieten. Das folgende Beispiel zeigt, wie das angeklickte Tab per Popup umbenannt werden kann:
/* Practical example: use the new tabRightClicked event to trigger a rename dialog
* for the clicked tab, similar to a context menu action.
*
* Demonstrates:
* - Detecting a right-click on a specific tab header via tabRightClicked.
* - Using an aguila popup with a proper buttons.bar() action bar to ask the user
* for a new title.
* - Updating the tab title by reassigning the child widget's `title` property.
*
* Note: Repeated right-clicks intentionally open multiple rename dialogs at the
* same time. Guarding against this is out of scope for this example.
*/
let aguila = require('common/aguila');
let buttons = require('/agorum/roi/customers/agorum.composite/js/lib/buttons');
let tabContainer = aguila.create({
type: 'agorum.tabContainer',
name: 'renameableTabContainer',
width: 560,
height: 340,
items: [
{
type: 'agorum.vbox',
title: 'Tab 1',
name: 'tab1',
items: [
{
type: 'agorum.composite.form.element.text',
name: 'tab1Hint',
label: 'Hint',
readOnly: true,
value: 'Right-click a tab header to rename it.',
},
],
},
{
type: 'agorum.vbox',
title: 'Tab 2',
name: 'tab2',
items: [
{
type: 'agorum.composite.form.element.text',
name: 'tab2Hint',
label: 'Hint',
readOnly: true,
value: 'Right-click a tab header to rename it.',
},
],
},
{
type: 'agorum.vbox',
title: 'Tab 3',
name: 'tab3',
items: [
{
type: 'agorum.composite.form.element.text',
name: 'tab3Hint',
label: 'Hint',
readOnly: true,
value: 'Right-click a tab header to rename it.',
},
],
},
],
});
/**
* Open a small popup asking the user for a new tab title. When the user confirms,
* the title of the tab at the given index is updated.
*
* @param {number} tabIndex Index of the tab to rename
*/
let openRenameDialog = tabIndex => {
let tabWidget = tabContainer.items[tabIndex];
if (!tabWidget) {
return;
}
let buttonBar = buttons.bar().ok({ name: 'apply', text: 'Apply' }).cancel().build();
let renameForm = aguila.create({
type: 'agorum.composite.form.basic',
name: 'renameForm',
width: 320,
labelPosition: 'top',
elements: [
{
type: 'agorum.composite.form.element.text',
name: 'newTitleInput',
label: 'New tab title',
value: tabWidget.title || '',
},
{ type: 'agorum.spacer', height: 16 },
buttonBar,
],
});
let closeDialog = () => {
renameForm.form.close();
};
let applyChange = () => {
let inputWidget = renameForm.down('newTitleInput');
let newTitle = (inputWidget.value || '').trim();
if (newTitle) {
tabWidget.title = newTitle;
}
closeDialog();
};
renameForm.on('action', action => {
if (action.submit) {
applyChange();
return;
}
switch (action.name) {
case 'apply':
applyChange();
break;
case 'cancel':
closeDialog();
break;
default:
break;
}
});
renameForm.popup({
type: 'agorum.form',
title: 'Rename tab',
width: 340,
height: 220,
});
setImmediate(() => {
renameForm.form.on('escape', () => {
closeDialog();
});
});
};
tabContainer.on('tabRightClicked', tabIndex => {
openRenameDialog(tabIndex);
});
tabContainer;
Das Event tabDblClicked lässt sich beispielsweise nutzen, um alle Eingabefelder innerhalb einer Registerkarte per Doppelklick zurückzusetzen.
/* Practical example: use tabDblClicked to reset the content of a tab.
*
* Demonstrates:
* - Detecting a double-click on a specific tab header via tabDblClicked.
* - Resetting form-element values inside the double-clicked tab without
* recreating the tab or the container.
* - Comparing the double-click with a regular click (activeTabChanged) that
* only switches the visible tab.
*/
let aguila = require('common/aguila');
let buildEditableTab = (title, name, defaultText) => ({
type: 'agorum.vbox',
title: title,
name: name,
items: [
{
type: 'agorum.composite.form.element.text',
name: name + 'Text',
label: 'Text field',
value: defaultText,
},
{
type: 'agorum.composite.form.element.number',
name: name + 'Number',
label: 'Number field',
integer: true,
value: 0,
},
{
type: 'agorum.composite.form.element.boolean',
name: name + 'Boolean',
label: 'Checkbox',
text: 'Enabled',
value: false,
},
{
type: 'agorum.composite.form.element.text',
name: name + 'Hint',
readOnly: true,
value: 'Double-click this tab header to reset all fields inside this tab.',
},
],
});
let tabContainer = aguila.create({
type: 'agorum.tabContainer',
name: 'resettableTabContainer',
width: 540,
height: 360,
items: [
buildEditableTab('Customer', 'customerTab', 'ACME Inc.'),
buildEditableTab('Contact', 'contactTab', 'John Doe'),
buildEditableTab('Notes', 'notesTab', 'Some notes about the customer.'),
],
});
/**
* Reset the state of all form elements inside the tab with the given index.
*
* @param {number} tabIndex Index of the tab to reset
*/
let resetTab = tabIndex => {
let tabWidget = tabContainer.items[tabIndex];
if (!tabWidget) {
return;
}
let baseName = tabWidget.name;
let textWidget = tabContainer.down(baseName + 'Text');
if (textWidget) {
textWidget.value = '';
}
let numberWidget = tabContainer.down(baseName + 'Number');
if (numberWidget) {
numberWidget.value = 0;
}
let booleanWidget = tabContainer.down(baseName + 'Boolean');
if (booleanWidget) {
booleanWidget.value = false;
}
};
tabContainer.on('tabDblClicked', tabIndex => {
resetTab(tabIndex);
});
tabContainer;