/*
* GxUI Library 2.0.1
* Copyright (c) 2009, Artech
* All rights reserved.
*
* GxUI Library is freely distributable under the terms of the BSD license.
*
*/
/// <reference path="..\..\Freezer\Ext\ext-all-dev.js" />
/**
* @class gxui.Toolbar
* Toolbar User Control. Wraps Ext.toolbar.Toolbar so it can be used from GeneXus.
* The control basically loads a SDT which contains the toolbar items. Consequently you will have to
* define a variable based on gxuiToolbar SDT which must be assigned to the {@link #Data} property of the control.
* This variable will have a collection of items (gxuiToolbarItem SDT) that will be displayed in the toolbar.
*
*
* #Basic Toolbar
* {@img Toolbar/gxuiToolbar.png Toolbar sample}
* The code below is an example of a Data Provider that produces a simple toolbar as the one shown in the image.
*
* gxuiToolbar
* {
* Buttons
* {
* Item
* {
* Id = !"DSP"
* Text = "Display"
* Tooltip = "Tooltip for Display Button"
* Type = gxuiToolbarItemTypes.Button
* Icon = ActionDisplay.Link()
* }
* Item
* {
* Id = !"UPD"
* Text = "Update"
* Tooltip = "Toltip for Update Button"
* Type = gxuiToolbarItemTypes.Button
* Icon = ActionUpdate.Link()
* }
* Item
* {
* Id = !"DLT"
* Text = "Delete"
* Tooltip = "Tooltip for Delete Button"
* Type = gxuiToolbarItemTypes.Button
* Icon = ActionDelete.Link()
* AskConfirmation = True
* Confirmation
* {
* Message = !"Please confirm this action."
* CancelButtonText = !"Cancel"
* OKButtonText = !"Delete"
* }
* }
* Item
* {
* Id = !"SEARCH"
* Text = "Search..."
* Tooltip = "Enter search query."
* Type = gxuiToolbarItemTypes.Edit
* }
* }
* }
*
*
* # Multi-level menu
* {@img Toolbar/gxuiToolbar2.png Toolbar sample}
*
* Example of a data provider to load the items shown in the above image.
*
* gxuiToolbar
* {
* Buttons
* {
* Item
* {
* Id = !"DSP"
* Text = "Display"
* Tooltip = "Tooltip for Display Button"
* Type = gxuiToolbarItemTypes.Menu
* Icon = ActionDisplay.Link()
* Items
* {
* Item
* {
* Id = !"DSP11"
* Text = "Display incoming calls"
* Tooltip = "Tooltip for display incoming calls button"
* Type = gxuiToolbarItemTypes.Button
* Icon = ActionDisplay.Link()
* }
* Item
* {
* Id = !"DSP12"
* Text = "Display outgoing calls"
* Tooltip = "Tooltip for display outgoing calls button"
* Type = gxuiToolbarItemTypes.Menu
* Icon = ActionDisplay.Link()
* Items
* {
* Item
* {
* Id = !"DSP121"
* Text = "Display outgoing calls - Today"
* Tooltip = "Tooltip for display outgoing calls Today button"
* Type = gxuiToolbarItemTypes.Button
* Icon = ActionDisplay.Link()
* }
* Item
* {
* Id = !"DSP122"
* Text = "Display outgoing calls - Yesterday"
* Tooltip = "Tooltip for display outgoing calls Yesterday button"
* Type = gxuiToolbarItemTypes.Button
* Icon = ActionDisplay.Link()
* }
* }
* }
* }
* }
* Item
* {
* Id = !"UPD"
* Text = "Update"
* Tooltip = "Toltip for Update Button"
* Type = gxuiToolbarItemTypes.Button
* Icon = ActionUpdate.Link()
* }
* Item
* {
* Id = !"DLT"
* Text = "Delete"
* Tooltip = "Tooltip for Delete Button"
* Type = gxuiToolbarItemTypes.Button
* Icon = ActionDelete.Link()
* AskConfirmation = True
* Confirmation
* {
* Message = !"Please confirm this action."
* CancelButtonText = !"Cancel"
* OKButtonText = !"Delete"
* }
* }
* Item
* {
* Id = !"SEARCH"
* Text = "Search..."
* Tooltip = "Enter search query."
* Type = gxuiToolbarItemTypes.Edit
* }
* }
* }
* #More information:#
* For more examples please see the [online KB][1].
* [1]: http://xev2.genexusserver.com/gxserver/action.aspx?1,RSSReader2.0:0:c9584656-94b6-4ccd-890f-332d11fc2c25:15
*
*/
Ext.define('gxui.Toolbar', {
extend: 'gxui.UserControl',
initialize: function () {
this.callParent();
this.ButtonPressedId = "";
this.EditFieldValue = "";
this.addEvents({
/**
* @event beforebuttonpressed
* Fires before a click on a toolbar Button (Type = "Button") is processed. Return false to cancel the default action.
* @param {gxui.UserControl} this
* @param {Ext.Toolbar.Button} btn Pressed button
* @param {Ext.EventObject} e
* @ignore
*/
"beforebuttonpressed": true,
/**
* @event buttonpressed
* Fires after a toolbar Button (Type = "Button") has been pressed.
* @param {gxui.UserControl} this
* @param {Ext.Toolbar.Button} btn Pressed button
* @param {Ext.EventObject} e
* @ignore
*/
"buttonpressed": true,
/**
* @event editfieldkeypress
* Fires after a key has been pressed in a toolbar Edit field (Type == "Edit").
* @param {gxui.UserControl} this
* @param {Ext.form.TextField} edit Edit field
* @param {Ext.EventObject} e
* @ignore
*/
"editfieldkeypress": true,
/**
* @event editfieldblur
* Fires after a toolbar Edit field (Type == "Edit") loses focus.
* @param {gxui.UserControl} this
* @param {Ext.form.TextField} edit Edit field
* @ignore
*/
"editfieldblur": true
});
// Register default Toolbar item resolvers
gxui.Toolbar.ItemResolvers.register({
"Button": function (toolbar, button) {
var config = {
id: toolbar.getUniqueButtonId(button.Id),
gxConfirmation: gxui.CBoolean(button.AskConfirmation) ? button.Confirmation : false,
cls: toolbar.getBtnCls(button),
enableToggle: gxui.CBoolean(button.EnableToggle),
pressed: gxui.CBoolean(button.Pressed),
disabled: gxui.CBoolean(button.Disabled),
hidden: gxui.CBoolean(button.Hidden),
handler: toolbar.buttonClickHandler,
isDropTarget: gxui.CBoolean(button.IsDropTarget),
scope: toolbar,
RefreshData: gxui.CBoolean(button.RefreshData)
};
gxui.tryPropertyMapping(config, button, {
"gxid": "Id",
"text": "Text",
"tooltip": "Tooltip",
"icon": "Icon",
"iconCls": "IconCls",
"rowspan": "RowSpan",
"colspan": "ColSpan",
"iconAlign": { property: "IconAlign", ignoreEmpty: true },
"arrowAlign": { property: "ArrowAlign", ignoreEmpty: true },
"scale": { property: "Scale", ignoreEmpty: true },
"width": { property: "Width", ignoreEmpty: true }
});
return config;
},
"Text": function (toolbar, button) {
return button.Text;
},
"Edit": function (toolbar, button) {
var edit = Ext.create('Ext.form.field.Text', {
id: toolbar.getUniqueButtonId(button.Id),
cls: button.Cls,
width: button.Width || 180,
disabled: gxui.CBoolean(button.Disabled),
hidden: gxui.CBoolean(button.Hidden),
enableKeyEvents: true,
value: button.Value || undefined
});
if (edit.Text != '')
edit.emptyText = button.Text;
edit.on({
"keypress": {
fn: function (field, e) {
this.fireEvent("editfieldkeypress", this, field, e);
if (e.getKey() == Ext.EventObject.ENTER) {
e.stopEvent();
this.editActionHandler(field);
}
},
scope: toolbar
},
"blur": {
fn: function (field) {
this.fireEvent("editfieldblur", this, field);
this.editActionHandler(field);
},
scope: toolbar
}
});
edit.gxid = button.Id;
return edit;
},
"Fill": function () {
return Ext.create('Ext.toolbar.Fill');
},
"Separator": function () {
return "-";
},
"Menu": function (toolbar, button) {
var menuItems = [];
if (button.Items) {
Ext.each(button.Items, function (item, index, allItems) {
menuItems.push(toolbar.getConfig(item));
});
}
var config = {
hidden: gxui.CBoolean(button.Hidden),
menu: {
items: menuItems,
ignoreParentClicks: true
},
cls: toolbar.getBtnCls(button),
disabled: gxui.CBoolean(button.Disabled)
};
gxui.tryPropertyMapping(config, button, {
"text": "Text",
"tooltip": "Tooltip",
"icon": "Icon",
"iconCls": "IconCls",
"rowspan": "RowSpan",
"colspan": "ColSpan",
"iconAlign": { property: "IconAlign", ignoreEmpty: true },
"arrowAlign": { property: "ArrowAlign", ignoreEmpty: true },
"scale": { property: "Scale", ignoreEmpty: true },
"width": { property: "Width", ignoreEmpty: true }
});
return config;
},
"SplitButton": function (toolbar, button) {
var splitButton = gxui.Toolbar.ItemResolvers.get(gxui.Toolbar.ItemType.Menu)(toolbar, button);
splitButton.gxid = button.Id;
splitButton.gxConfirmation = gxui.CBoolean(button.AskConfirmation) ? button.Confirmation : false;
splitButton.xtype = 'splitbutton';
splitButton.enableToggle = gxui.CBoolean(button.EnableToggle);
splitButton.pressed = gxui.CBoolean(button.Pressed);
if (gxui.CBoolean(button.EnableToggle)) {
splitButton.toggleHandler = toolbar.buttonClickHandler;
}
else {
splitButton.handler = toolbar.buttonClickHandler;
}
splitButton.scope = toolbar;
return splitButton;
},
"Group": function (toolbar, button) {
var groupItems = [];
if (button.Items) {
Ext.each(button.Items, function (item, index, allItems) {
groupItems.push(toolbar.getConfig(item));
});
}
var config = {
xtype: 'buttongroup',
defaults: {},
items: groupItems
};
gxui.tryPropertyMapping(config, button, {
"title": "Text",
"columns": "GroupColumns"
});
gxui.tryPropertyMapping(config.defaults, button, {
"iconAlign": { property: "IconAlign", ignoreEmpty: true },
"arrowAlign": { property: "ArrowAlign", ignoreEmpty: true },
"scale": { property: "Scale", ignoreEmpty: true }
});
return config;
},
"ComboBox": function (toolbar, comboBox) {
var config = {
xtype: 'combobox',
gxid: comboBox.Id,
cls: toolbar.getBtnCls(comboBox),
disabled: gxui.CBoolean(comboBox.Disabled),
hidden: gxui.CBoolean(comboBox.Hidden),
editable: true,
triggerAction: 'all',
selectOnFocus: true,
disableKeyFilter: false,
forceSelection: true,
queryMode: 'local',
store: {
autoDestroy: true,
fields: ['id', 'dsc'],
data: []
},
displayField: 'dsc',
valueField: 'id',
listeners: {
'select': function (field) {
this.editActionHandler(field);
},
scope: toolbar
}
};
if (comboBox.Items) {
for (var i = 0, len = comboBox.Items.length; i < len; i++) {
config.store.data.push({
id: comboBox.Items[i].Id,
dsc: comboBox.Items[i].Text
});
}
}
gxui.tryPropertyMapping(config, comboBox, {
"gxid": "Id",
"text": "Text",
"tooltip": "Tooltip",
"icon": "Icon",
"iconCls": "IconCls",
"rowspan": "RowSpan",
"colspan": "ColSpan",
"iconAlign": { property: "IconAlign", ignoreEmpty: true },
"arrowAlign": { property: "ArrowAlign", ignoreEmpty: true },
"scale": { property: "Scale", ignoreEmpty: true },
"width": { property: "Width", ignoreEmpty: true },
"value": { property: "Value", ignoreEmpty: true },
"emptyText": { property: "Text", ignoreEmpty: true }
});
return config;
}
});
},
//private
SetData: function (data) {
this.Data = data;
},
//private
GetData: function (data) {
return this.Data;
},
//private
GetToolbar: function (add) {
return this.m_toolbar;
},
onRender: function () {
this.createToolbar().render(this.getContainerControl());
},
onRefresh: function () {
this.refreshButtons(this.Data.Buttons, this.m_toolbar.items);
},
getUnderlyingControl: function () {
return this.m_toolbar;
},
//private
createToolbar: function (options) {
var vertical = false,
itemId;
if (options) {
if (options.id) {
this.getUniqueId = function () {
return options.id;
};
}
if (options.data) {
this.SetData(options.data);
}
if (options.container) {
options.container.buttonActionHandler = this.buttonActionHandler;
options.container.editActionHandler = this.editActionHandler;
this.buttonActionHandler = Ext.bind(this.buttonActionHandler, options.container);
this.editActionHandler = Ext.bind(this.editActionHandler, options.container);
}
if (options.on) {
this.on(options.on);
}
if (options.vertical)
vertical = options.vertical;
itemId = options.itemId;
}
var config = {
id: this.getUniqueId(),
stateful: false,
items: this.createButtons(),
listeners: {},
vertical: vertical,
itemId: itemId
};
if (options && options.container) {
config.dock = options.dock || 'top';
}
if (!options || !options.container) {
if (this.Width != 'auto') {
config.width = parseInt(this.Width, 10);
}
if (this.Height != 'auto') {
config.height = parseInt(this.Height, 10);
}
}
config.listeners['afterrender'] = {
fn: this.adjustWidth,
delay: 300
};
config.listeners.scope = this;
this.m_toolbar = Ext.create('Ext.toolbar.Toolbar', config);
return this.m_toolbar;
},
//private
createButtons: function () {
var toolbarItems = [];
if (this.Data && this.Data.Buttons) {
Ext.each(this.Data.Buttons, function (item, index, allItems) {
if (!item.Type) {
item.Type = gxui.Toolbar.ItemType.Button;
}
toolbarItems.push(this.getConfig(item));
if (this.SeparateAll && allItems[index + 1])
toolbarItems.push('-');
}, this);
}
return toolbarItems;
},
//private
buttonClickHandler: function (btn, e) {
if (this.fireEvent("beforebuttonpressed", this, btn, e) !== false) {
if (btn.gxConfirmation) {
var processResult = function (option, text) {
if (option == 'ok')
this.buttonActionHandler(btn, e);
};
var msgBox = new Ext.window.MessageBox({
buttonText: {
ok: btn.gxConfirmation.OKButtonText,
cancel: btn.gxConfirmation.CancelButtonText
},
listeners: {
'afterrender': function (mb) {
// Put focus on Cancel button by default.
mb.defaultFocus = 3;
}
}
});
msgBox.show({
title: btn.gxConfirmation.Title,
msg: btn.gxConfirmation.Message,
buttons: Ext.Msg.OKCANCEL,
fn: processResult,
scope: this,
animateTarget: btn.getEl(),
icon: Ext.Msg.QUESTION
});
}
else {
this.buttonActionHandler(btn, e);
}
this.fireEvent("buttonpressed", this, btn, e);
}
},
//private
buttonActionHandler: function (btn, e) {
/**
* @event ButtonPressed
* Fires after a toolbar item has been pressed. The only items that fire this event are Button and SplitButton.
* The following properties are set when the event is fired:
*
* - {@link #ButtonPressedId}
*/
if (this.ButtonPressed) {
this.ButtonPressedId = btn.gxid;
this.ButtonPressed();
}
},
//private
editActionHandler: function (field) {
this.EditFieldValue = field.getValue();
this.buttonActionHandler(field);
},
//private
getConfig: function (button) {
if (button.id && button.id.indexOf("ext") == 0)
return button;
if (!button.Type)
button.Type = gxui.Toolbar.ItemType.Button;
var resolver = gxui.Toolbar.ItemResolvers.get(button.Type) || gxui.Toolbar.ItemResolvers.get(gxui.Toolbar.ItemType.Button);
if (resolver)
return resolver(this, button);
},
//private
defineBtnsDropTarget: function () {
this.m_toolbar.items.each(function (item, pos) {
if (item.type == "button" && item.isDropTarget) {
var dt = new Ext.dd.DropTarget(item.getEl(), { ddGroup: 'GridDD' });
dt._btn = item;
dt._scope = this;
dt.notifyOver = function (source, e, data) {
if (data.grid) {
return 'x-dd-drop-ok';
}
return 'x-dd-drop-nodrop';
};
dt.notifyDrop = function (source, e, data) {
if (data.grid) {
this._scope.buttonActionHandler(this._btn);
return true;
}
return false;
};
dt.notifyEnter = function (source, e, data) {
if (data.grid) {
return 'x-dd-drop-ok';
}
return 'x-dd-drop-nodrop';
};
}
},
this);
},
//private
refreshButtons: function (buttons, renderedButtons) {
var i = 0;
var ItemType = gxui.Toolbar.ItemType;
renderedButtons.each(function (renderedBtn) {
var button = buttons[i];
if (button) {
if (!gxui.CBoolean(button.Disabled) && renderedBtn.disabled) {
if (renderedBtn.enable)
renderedBtn.enable();
}
else {
if (gxui.CBoolean(button.Disabled) && !renderedBtn.disabled) {
if (renderedBtn.disable)
renderedBtn.disable();
}
}
if (gxui.CBoolean(button.Hidden) && !renderedBtn.hidden) {
if (renderedBtn.hide)
renderedBtn.hide();
}
else {
if (!gxui.CBoolean(button.Hidden) && renderedBtn.hidden) {
if (renderedBtn.show)
renderedBtn.show();
}
}
if (button.Type == ItemType.Text)
renderedBtn.setText(button.Text);
if ((button.Type == ItemType.Menu || button.Type == ItemType.SplitButton) && button.Items && renderedBtn.menu) {
this.refreshButtons(button.Items, renderedBtn.menu.items);
}
}
i += 1;
}, this)
this.adjustWidth(this.m_toolbar);
},
//private
getUniqueButtonId: function (btnId) {
return this.getUniqueId() + "_btn_" + btnId;
},
//private
findItem: function (id, items) {
var ItemType = gxui.Toolbar.ItemType;
var searchedItem;
Ext.each(items, function (item) {
if (item.Id == id) {
searchedItem = item;
}
else {
if ((item.Type == ItemType.Menu || item.type == ItemType.SplitButton) && item.Items) {
searchedItem = this.findItem(id, item.Items);
}
}
if (searchedItem) {
return false;
}
}, this);
return searchedItem;
},
//private
changeItemPropertyValue: function (itemId, propertyId, propertyValue) {
var item = this.findItem(itemId, this.Data.Buttons);
if (item) {
item[propertyId] = propertyValue;
}
return item;
},
//private
getBtnCls: function (btn) {
if (!btn.Cls) {
if (btn.Icon) {
return (btn.Text) ? "x-btn-text-icon" : "x-btn-icon";
}
else {
return "x-btn-text";
}
}
return btn.Cls;
},
adjustWidth: function (toolbar) {
if (!toolbar.ownerCt) {
if (this.Width == 'auto') {
var lastItem = null;
toolbar.items.each(function (item) {
if (item.isVisible())
lastItem = item;
})
if (lastItem) {
toolbar.setWidth(100); // WA
width = lastItem.el.getLeft(true) + lastItem.el.getWidth() + toolbar.el.getFrameWidth('l r');
toolbar.setWidth(width);
}
}
}
},
methods: {
// Methods
/**
* Changes the current list of toolbar items with a new one and render it.
* @param {gxuiToolbar} toolbar gxuiToolbar configuration object containing the list of new toolbar items to render
* @method
*/
ChangeToolbar: function (toolbarData, id, container) {
this.m_toolbar.removeAll();
this.m_toolbar.add(this.createButtons());
return this.m_toolbar;
},
/**
* Disable a toolbar item by id
* @param {String} itemId Toolbar item id
* @method
*/
DisableItem: function (itemId) {
this.changeItemPropertyValue(itemId, "Disabled", true);
this.refreshButtons(this.Data.Buttons, this.m_toolbar.items);
},
/**
* Enable a toolbar item by id
* @param {String} itemId Toolbar item id
* @method
*/
EnableItem: function (itemId) {
this.changeItemPropertyValue(itemId, "Disabled", false);
this.refreshButtons(this.Data.Buttons, this.m_toolbar.items);
},
/**
* Hide a toolbar item by id
* @param {String} itemId Toolbar item id
* @method
*/
HideItem: function (itemId) {
this.changeItemPropertyValue(itemId, "Hidden", true);
this.refreshButtons(this.Data.Buttons, this.m_toolbar.items);
},
/**
* Shows a hidden toolbar item by id
* @param {String} itemId Toolbar item id
* @method
*/
ShowItem: function (itemId) {
this.changeItemPropertyValue(itemId, "Hidden", false);
this.refreshButtons(this.Data.Buttons, this.m_toolbar.items);
}
}
});
/**
* @class gxui.Toolbar.ItemType
* Standard gxui.Toolbar item types
* @ignore
*/
gxui.Toolbar.ItemType = {
Button: "Button",
Text: "Text",
Edit: "Edit",
Fill: "Fill",
Separator: "Separator",
SplitButton: "SplitButton",
Group: "Group"
};
/**
* @class gxui.Toolbar.ItemResolvers
* gxui.Toolbar.ItemResolvers stores the list of toolbar item resolvers for {@link gxui.Toolbar}. A resolver maps
* a {@link gxui.Toolbar} item configuration with a Ext.toolbar.Toolbar component configuration or object.
* New types of items can be added to {@link gxui.Toolbar}. For each new type, a resolver must be registered using
* the register method.
* @singleton
* @ignore
*/
gxui.Toolbar.ItemResolvers = {
// private
items: {},
/**
* Register a new {@link gxui.Toolbar} item resolver.
* @param {String} type Toolbar item type
* @param {Function} resolver Resolver function that maps a {@link gxui.Toolbar} configuration with a Ext.toolbar.Toolbar component configuration or object.
* @method
*/
register: function (type, resolver) {
if (typeof (type) == 'string')
this.items[type] = resolver;
else if (typeof (type) == 'object') {
for (var item in type) {
if (typeof (type[item]) == 'function') {
this.items[item] = type[item];
}
}
}
},
/**
* Unregister a {@link gxui.Toolbar} item resolver.
* @param {String} type Toolbar item type
* @method
*/
unregister: function (type) {
delete this.items[type];
},
/**
* Get an existing {@link gxui.Toolbar} item resolver, by name.
* @param {String} type Toolbar item type
* @method
*/
get: function (type) {
return this.items[type];
}
};