* Implements functions for rendering and work with SideBar panel.
* Example:
*
* var sideBar = Ext.create("Terrasoft.SideBar", {
* items: [
* {
* caption: "some caption",
* tag: 'someTag',
* imageUrl: "http://website.com/image.png",
* href: "http://google.com"
* }
* ],
* selectedItemIndex: 0,
* collapsed: {
* bindTo: "Collapsed"
* },
* itemSelected: {
* bindTo: "someFunction
* },
* tips: [
* {
* tip: {
* content: "some content",
* displayMode: "narrow",
* tag: "someTag",
* markerValue: "some marker value"
* },
* settings: {
* alignEl: "getItemImageEl"
* }
* }
* ]
* });
*
*/
Ext.define("Terrasoft.controls.SideBar", {
alternateClassName: "Terrasoft.SideBar",
extend: "Terrasoft.Component",
* @inheritdoc Terrasoft.controls.Component#tpl
*/
tpl: [
/* jshint white:false */
/* jshint quotmark:false */
/* jscs: disable */
'<ul id="{id}-wrap" class="ts-sidebar-list ts-box-sizing" style="{wrapStyle}">', '{%this.renderItems(out, values)%}', '</ul>'
/* jscs: enable */
/* jshint white:true */
/* jshint quotmark:true */
],
* Template for side bar item.
* @protected
* @type {String[]}
*/
itemTpl: [
/* jshint quotmark: false */
/* jshint white: false */
/* jscs: disable */
'<tpl if="visible != false">', '<li data-item-index="{itemIndex}"', '<tpl if="isSelected == true">', 'class="ts-sidebar-selected-item"', '</tpl>', '>', '<tpl if="href"><a target="_self" class="sidebar-item-link" href="{href}"></tpl>', '<div id="sidebar-item-wrapper-{itemIndex}" class="ts-sidebar-item-wrapper">', '<div id="sidebar-item-image-{itemIndex}" class="ts-sidebar-item-image" data-item-marker="{caption}" ' + 'style="background-image:url({imageUrl})" <tpl foreach="domAttributes">{$}="{.}"</tpl>></div>', '<div id="sidebar-item-text-{itemIndex}" class="ts-sidebar-item-text"> {caption} ', '</div>', '</div>', '<tpl if="href"></a></tpl>', '</li>', '</tpl>'
/* jscs: enable */
/* jshint white:true */
/* jshint quotmark:true */
],
* Template for side bar item content.
* @protected
* @type {String[]}
*/
itemContextTpl: [
/*jshint quotmark:false */
/*jscs: disable*/
'<tpl if="visible != false">', '{caption}', '</tpl>'
/*jscs: enable*/
/*jshint quotmark:true */
],
* Template for hint item.
* @protected
* @type {String[]}
*/
captionHintTpl: [
/*jshint quotmark:false */
/* jshint white:false */
/*jscs: disable*/
'<div id="sidebar-item-text-{itemIndex}-hint" class="ts-sidebar-item-text-hint"> {caption}', ' </div>'
/*jscs: enable*/
/* jshint white:true */
/*jshint quotmark:true */
],
* List of side bar items.
* @private
* @param {String} items.caption Caption of side bar item.
* @param {String} items.tag Item tag.
* @param {Boolean} items.visible Is item visible flag.
* @type {Array}
*/
items: null,
* Selected side bar item. Number of menu item is equals to index of {@link #items}.
* The numbering starts with zero.
* @private
* @type {Number}
*/
selectedItemIndex: -1,
* Max width of element.
* @type {String}
*/
maxWidth: "",
* Min width of element.
* @type {String}
*/
minWidth: "",
* Side bar state.
* @type {Boolean}
*/
collapsed: false,
* Css-class name for collapsed item hint.
* @protected
* @type {String}
*/
hintOpacityClass: "ts-sidebar-item-text-hint-opacity",
* @inheritdoc Terrasoft.controls.Component#init
* @override
*/
init: function () {
this.callParent(arguments);
this.addEvents(
* @event
* Event to change the selection of a new menu item.
* Called when you click on a new menu item.
* @param {Number} selectedItemIndex The number of the selected item.
* @param {String} tag
*/
"itemSelected");
},
* @inheritdoc Terrasoft.controls.Component#getTplData
* @override
*/
getTplData: function () {
var tplData = this.callParent(arguments);
tplData.renderItems = this.renderItems;
this.styles = this.getStyles();
this.selectors = {
wrapEl: "#" + this.id + "-wrap"
};
return tplData;
},
* Returns styles for building element template.
* @protected
* @return {Object} Config object with css-styles.
*/
getStyles: function () {
var styles = {};
var wrapStyle = styles.wrapStyle = {};
var maxWidth = this.maxWidth;
var minWidth = this.minWidth;
if (maxWidth) {
wrapStyle.maxWidth = maxWidth;
}
if (minWidth) {
wrapStyle.minWidth = minWidth;
}
return styles;
},
* @inheritdoc Terrasoft.controls.Component#initDomEvents
* @override
*/
initDomEvents: function () {
this.callParent(arguments);
var wrapEl = this.getWrapEl();
wrapEl.on("click", this.onMenuClick, this);
},
* @inheritdoc Terrasoft.controls.Component#clearDomListeners
* @override
*/
clearDomListeners: function () {
this.wrapEl.un("click", this.onMenuClick, this);
this.callParent(arguments);
},
* Subscribes for mouse events on each item in sidebar.
* @private
* @param {Object} item Sidebar item.
* @param {Number} itemIndex Index of item.
*/
initItemEvents: function (item, itemIndex) {
var itemImageElSelector = Ext.String.format("#sidebar-item-wrapper-{0}", itemIndex);
var wrapEl = this.getWrapEl();
var itemImageEl = wrapEl.down(itemImageElSelector);
if (itemImageEl) {
itemImageEl.on("mouseenter", this.onMouseEnter, this);
itemImageEl.on("mouseleave", this.onMouseLeave, this);
}
},
* Unsubscribes for mouse events on each item in sidebar.
* @private
* @param {Object} item Sidebar item.
* @param {Number} itemIndex Index of item.
*/
clearItemEvents: function (item, itemIndex) {
var itemImageElSelector = Ext.String.format("#sidebar-item-wrapper-{0}", itemIndex);
var wrapEl = this.getWrapEl();
var itemImageEl = wrapEl.down(itemImageElSelector);
if (itemImageEl) {
itemImageEl.un("mouseenter", this.onMouseEnter, this);
itemImageEl.un("mouseleave", this.onMouseLeave, this);
}
},
* Handler for menu item click.
* If selected new item, changes it's style and fires event {@link #itemSelected}.
* @protected
* @param {Event} e Menu item click event.
* @param {HTMLElement} el Menu item click element.
*/
onMenuClick: function (e, el) {
if (e.ctrlKey) {
return;
}
var element = this.getParentElement("LI", el);
if (element) {
var canExecute = this.canExecute({
method: this.onMenuClick,
args: arguments
});
if (canExecute === false) {
return;
}
var selectedItemIndex = element.getAttribute("data-item-index");
selectedItemIndex = parseInt(selectedItemIndex, 10);
if (this.selectedItemIndex !== selectedItemIndex) {
this.setSelectedItem(selectedItemIndex);
}
var tag = this.items[selectedItemIndex].tag;
this.fireEvent("itemSelected", selectedItemIndex, tag);
}
},
* Handler for 'mouseenter' event on sidebar image element.
* When {@link #collapsed} is collapsed, renders item hint text element near the current item.
* @protected
* @param {Event} e Mouseenter event.
*/
onMouseEnter: function (e) {
if (!this.collapsed) {
return;
}
this.showCaptionHint(e);
},
* Handler for 'mouseleave' event on sidebar image element.
* When {@link #collapsed} is collapsed, removes rendered item hint text element.
* @protected
* @param {Event} e Mouseleave event.
*/
onMouseLeave: function (e) {
if (!this.collapsed) {
return;
}
this.hideCaptionHint(e);
},
* Returns parent dom element.
* @private
* @param {String} selector Selector for find.
* @param {HTMLElement} target Target element where to find.
* @return {HTMLElement} Founded element.
*/
getParentElement: function (selector, target) {
var element = Ext.get(target);
var wrapEl = this.getWrapEl();
return element.findParent(selector, wrapEl, true);
},
* Shows sidebar item hint element.
* @protected
* @param {Event} e Browser event.
*/
showCaptionHint: function (e) {
var element = this.getParentElement("LI", e.target);
if (!element) {
return;
}
var hoverItemIndex = element.getAttribute("data-item-index");
hoverItemIndex = parseInt(hoverItemIndex, 10);
var item = this.getItemConfig(hoverItemIndex);
var tplData = {
caption: item.caption,
itemIndex: hoverItemIndex
};
var html = this.generateItemHtml(tplData, this.captionHintTpl);
var body = Ext.getBody();
var appendEl = Ext.DomHelper.append(body, html);
this.setElPosition(e, appendEl);
},
* Sets position for sidebar item hint element.
* @private
* @param {Event} e Browser event.
* @param {HTMLElement} element Element for positioning.
*/
setElPosition: function (e, element) {
var targetEl = Ext.get(e.target);
var el = Ext.get(element);
var targetElBox = targetEl.getBox();
el.setStyle({
left: targetElBox.left + targetElBox.right + "px",
top: targetElBox.top + "px"
});
el.addCls(this.hintOpacityClass);
},
* Removes sidebar item hint element.
* @protected
* @param {Event} e Browser event.
*/
hideCaptionHint: function (e) {
var element = this.getParentElement("LI", e.target);
if (!element) {
return;
}
var hoverItemIndex = element.getAttribute("data-item-index");
hoverItemIndex = parseInt(hoverItemIndex, 10);
this.removeHintEl(hoverItemIndex);
},
* Removes hint element.
* @private
* @param {Number} index Index of element.
*/
removeHintEl: function (index) {
var elTpl = Ext.String.format("#sidebar-item-text-{0}-hint", index);
var el = Ext.get(Ext.DomQuery.selectNode(elTpl));
if (el) {
el.remove();
}
},
* @inheritdoc Terrasoft.controls.Component#onDestroy
* @override
*/
onDestroy: function () {
this.items.forEach(function (item, index) {
this.removeHintEl(index);
}, this);
this.callParent(arguments);
},
* Generates HTML-markup for all items, when renders by default tpl.
* @protected
* @return {String[]} HTML-markup.
*/
getItemsRenderTemplateTree: function () {
var items = this.items;
var itemsTree = [];
var selectedItemIndex = this.selectedItemIndex;
var item, itemTplConfig, html, isSelected;
for (var i = 0, length = items.length; i < length; i++) {
item = items[i];
isSelected = selectedItemIndex === i;
itemTplConfig = this.generateItemTplConfig(item, i, isSelected);
html = this.generateItemHtml(itemTplConfig);
itemsTree.push(html);
}
return itemsTree;
},
* Creates config for building HTML-markup of the menu item.
* @protected
* @param {Object} itemConfig Menu item config.
* @param {Number} itemIndex Menu item index.
* @param {Boolean} isSelected Is menu item selected flag.
* @return {Object} Config object for building HTML-markup.
*/
generateItemTplConfig: function (itemConfig, itemIndex, isSelected) {
var itemTplData = this._getItemTplData(itemConfig);
itemTplData.visible = itemConfig.visible;
itemTplData.itemIndex = itemIndex;
itemTplData.isSelected = isSelected;
return itemTplData;
},
* Gets tpl data of the menu item.
* @private
* @param {Object} itemConfig Menu item config.
* @return {Object} Tpl data of the menu item.
*/
_getItemTplData: function (itemConfig) {
var itemTplData = {};
var itemTplMap = this.itemTplMap;
for (var i = 0, length = itemTplMap.length; i < length; i++) {
var property = itemTplMap[i];
var propertyValue = itemConfig[property];
propertyValue = Ext.isObject(propertyValue) ? Terrasoft.encodeHtmlObjectValues(propertyValue) : Terrasoft.encodeHtml(propertyValue);
itemTplData[property] = propertyValue;
}
return itemTplData;
},
* Renders side bar items. Uses in {@link #tpl}.
* @protected
* @param {String[]} buffer Buffer for generating HTML.
* @param {Object} renderData Config object for building tpl.
*/
renderItems: function (buffer, renderData) {
var self = renderData.self;
var itemsTree = self.getItemsRenderTemplateTree();
Ext.DomHelper.generateMarkup(itemsTree, buffer);
},
* Generates HTML-markup for side bar item.
* @protected
* @param {Object} tplData Config for building HTML-markup.
* @param {String[]} [itemTpl] Template for building HTML-markup, by defaults equals to {@link #itemTpl}.
*/
generateItemHtml: function (tplData, itemTpl) {
itemTpl = itemTpl || this.itemTpl;
var tpl = new Ext.XTemplate(itemTpl);
return tpl.apply(tplData);
},
* @inheritdoc Terrasoft.controls.Component#onAfterRender
* @override
*/
onAfterRender: function () {
this.callParent(arguments);
var wrapEl = this.getWrapEl();
wrapEl.unselectable();
},
* @inheritdoc Terrasoft.controls.Component#onAfterReRender
* @override
*/
onAfterReRender: function () {
this.callParent(arguments);
var wrapEl = this.getWrapEl();
wrapEl.unselectable();
},
* Updates side bar items config.
* @param {Object[]} items Array of new side bar items.
*/
updateItems: function (items) {
this.items = Ext.Object.merge([], items);
this.safeRerender();
},
* Updates side bar menu item.
* @param {Number} itemIndex Index of the item.
* @param {Object} itemConfig Config object for item.
*/
updateItem: function (itemIndex, itemConfig) {
var items = this.items;
var length = items.length;
if (itemIndex > length || itemIndex < 0) {
return;
}
Ext.Object.merge(items[itemIndex], itemConfig);
this.safeRerender();
},
* Sets selected side bar item.
* @param {Number} itemIndex Index of new selected item.
*/
setSelectedItem: function (itemIndex) {
var maxIndex = this.items.length;
if (this.selectedItemIndex === itemIndex || itemIndex < 0 || itemIndex > maxIndex) {
return;
}
this.selectedItemIndex = itemIndex;
var oldSelectedItemIndex = Ext.query(".ts-sidebar-selected-item")[0];
var newSelectedItemIndex = Ext.query("li[data-item-index='" + itemIndex + "']")[0];
var domUtils = Terrasoft.utils.dom;
if (oldSelectedItemIndex) {
domUtils.removeClassName(oldSelectedItemIndex, "ts-sidebar-selected-item");
}
if (newSelectedItemIndex) {
domUtils.addClassName(newSelectedItemIndex, "ts-sidebar-selected-item");
}
},
* Sets min or max width of the element.
* @param {String} width New width.
* @param {String} prefix Prefix which equals 'min' for min width and 'max' for max width.
*/
setMinMaxWidth: function (width, prefix) {
var suffix = "Width";
var widthName = prefix + suffix;
var currentWidth = this[widthName];
if (currentWidth === undefined || currentWidth === width) {
return;
}
this[widthName] = width;
if (this.rendered) {
var el = this.getWrapEl();
el.dom.style[widthName] = width;
}
},
* Returns index of the selected item.
* @return {Number} Index of the selected item.
*/
getSelectedItemIndex: function () {
return this.selectedItemIndex;
},
* Returns object config of the element with itemIndex.
* @param {Number} itemIndex Index of the element.
* @return {Object} Config object with index itemIndsex.
*/
getItemConfig: function (itemIndex) {
if (itemIndex < 0) {
return null;
}
return this.items[itemIndex];
},
* Returns list of objects with sidebar item configs.
* @return {Array} List of objects.
*/
getItems: function () {
return Terrasoft.deepClone(this.items);
},
* Returns Ext.Element for menu item by tag.
* @param {String} tag Tag of the menu item.
* @return {Ext.dom.Element} Menu item element.
*/
getItemImageEl: function (tag) {
var items = this.items;
var itemIndex;
for (var i in items) {
var item = items[i];
if (item.tag === tag) {
itemIndex = i;
break;
}
}
var itemImageEl = null;
if (Ext.isDefined(itemIndex)) {
var itemImageElSelector = Ext.String.format("#sidebar-item-image-{0}", itemIndex);
var wrapEl = this.getWrapEl();
itemImageEl = wrapEl.down(itemImageElSelector);
}
return itemImageEl;
},
* @inheritdoc Terrasoft.controls.Component#getBindConfig
* @override
*/
getBindConfig: function () {
var binding = this.callParent(arguments);
var sideBarBindings = {
collapsed: {
changeMethod: "setCollapsed"
}
};
Ext.apply(sideBarBindings, binding);
return sideBarBindings;
},
* Collapsed change handler.
* @param {Boolean} collapsed Property value.
*/
setCollapsed: function (collapsed) {
if (this.collapsed === collapsed) {
return;
}
this.collapsed = collapsed;
}
});