messengercustom-servicesmacoslinuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskypefacebook-workplaceoutlookemailmicrosoft-teamsdiscord
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
445 lines
16 KiB
445 lines
16 KiB
9 years ago
|
Ext.define('Ext.app.bindinspector.ComponentList', {
|
||
|
alias: 'widget.bindinspector-componentlist',
|
||
|
extend: 'Ext.tree.Panel',
|
||
|
|
||
|
requires: [
|
||
|
'Ext.form.field.Text'
|
||
|
],
|
||
|
|
||
|
rootVisible: false,
|
||
|
title: 'Component Tree',
|
||
|
hideHeaders: true,
|
||
|
|
||
|
bindingsIconCls: Ext.baseCSSPrefix + 'bindings-icon',
|
||
|
vmIconCls: Ext.baseCSSPrefix + 'vm-icon',
|
||
|
missingDataCls: Ext.baseCSSPrefix + 'bindinspector-missing-data',
|
||
|
filterVisibleCls: Ext.baseCSSPrefix + 'bindinspector-filter-visible',
|
||
|
lastItemCls: Ext.baseCSSPrefix + 'bindinspector-last-item',
|
||
|
|
||
|
bindingsIcon: '☍',
|
||
|
vmIcon: '☶',
|
||
|
|
||
|
initComponent: function() {
|
||
|
var me = this,
|
||
|
nodes = [];
|
||
|
|
||
|
me.viewConfig = {
|
||
|
toggleOnDblClick: false,
|
||
|
getRowClass: function (record, index, rowParams, store) {
|
||
|
var cls = [];
|
||
|
// decoration for items found when filtering
|
||
|
if (record.get('filtervisible')) {
|
||
|
cls.push(me.filterVisibleCls);
|
||
|
}
|
||
|
// decoration for items with no associated data
|
||
|
if (record.get('sansData')) {
|
||
|
cls.push(me.missingDataCls);
|
||
|
}
|
||
|
// decoration for the last item in the tree (adds a shadow for modern browsers)
|
||
|
if (index === store.getCount() - 1) {
|
||
|
cls.push(me.lastItemCls);
|
||
|
}
|
||
|
return cls.join(' ');
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// build the component node hierarchy
|
||
|
Ext.Array.forEach(me.components, function(comp) {
|
||
|
nodes.push(me.buildNode(comp));
|
||
|
}, me);
|
||
|
|
||
|
me.store = {
|
||
|
model: me.Model,
|
||
|
root: {
|
||
|
expanded: true,
|
||
|
children: nodes
|
||
|
}
|
||
|
};
|
||
|
|
||
|
me.columns = [{
|
||
|
// used by the Container.onVMSearchClick() method when showing the source VMs for a given data point
|
||
|
itemId: 'srcVMIndicator',
|
||
|
width: 40,
|
||
|
hidden: true,
|
||
|
renderer: me.srcVMIndicator,
|
||
|
scope: me
|
||
|
}, {
|
||
|
xtype: 'treecolumn',
|
||
|
dataIndex: 'text',
|
||
|
flex: 1
|
||
|
}];
|
||
|
|
||
|
me.dockedItems = [{
|
||
|
// the toolbar for searching within the component list
|
||
|
xtype: 'toolbar',
|
||
|
itemId: 'queryFieldTb',
|
||
|
dock: 'top',
|
||
|
items: [{
|
||
|
xtype: 'textfield',
|
||
|
reference: 'queryField',
|
||
|
itemId: 'queryField',
|
||
|
emptyText: 'simple search by reference / ID or use a component query...',
|
||
|
flex: 1,
|
||
|
triggers: {
|
||
|
clear: {
|
||
|
cls: Ext.baseCSSPrefix + 'form-clear-trigger',
|
||
|
handler: function(field) {
|
||
|
var tree = field.up('treepanel');
|
||
|
|
||
|
field.reset();
|
||
|
tree.clearComponentFilter();
|
||
|
field.focus();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
listeners: {
|
||
|
change: {
|
||
|
fn: me.filterComponentTree,
|
||
|
buffer: 250,
|
||
|
scope: me
|
||
|
},
|
||
|
afterrender: {
|
||
|
fn: function (field) {
|
||
|
var tbEl = field.up('toolbar').getEl();
|
||
|
|
||
|
// set up the toolip for the component list filter field
|
||
|
field.mon(tbEl, 'mouseenter', function () {
|
||
|
var tip = me.bindingsTip,
|
||
|
showAt, x, y;
|
||
|
|
||
|
tip.stopAnimation();
|
||
|
tip.update('<b>Simple Search</b><br>Enter the string matching the reference or ID of the target component<hr><b>Component Query</b><br>Enter a component query string to find any items matching the query');
|
||
|
tip.setTarget(tbEl);
|
||
|
tip.show();
|
||
|
x = tip.getX();
|
||
|
y = tip.getY();
|
||
|
showAt = tip.getAlignToXY(tbEl, 'l-r');
|
||
|
tip.animate({
|
||
|
from: {
|
||
|
opacity: 0,
|
||
|
x: showAt[0] + 20,
|
||
|
y: showAt[1]
|
||
|
},
|
||
|
to: {
|
||
|
opacity: 1,
|
||
|
x: showAt[0] + 10,
|
||
|
y: showAt[1]
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
},
|
||
|
scope: me
|
||
|
}
|
||
|
}
|
||
|
}]
|
||
|
}, {
|
||
|
// toolbar used by Container.onVMSearchClick()
|
||
|
// is shown when the results in the Component List are filtered by the ViewModelDetail's searched data point
|
||
|
xtype: 'toolbar',
|
||
|
cls: Ext.baseCSSPrefix + 'vm-results-tb',
|
||
|
itemId: 'vmQueryResultsTb',
|
||
|
hidden: true,
|
||
|
dock: 'top',
|
||
|
defaultButtonUI: 'default',
|
||
|
items: ['->', {
|
||
|
text: 'Clear VM Filter',
|
||
|
// restores the original filter toolbar
|
||
|
handler: function () {
|
||
|
//console.log(this.up('#vmQueryResultsTb'));
|
||
|
var tb = this.up('#vmQueryResultsTb'),
|
||
|
componentList = tb.up('bindinspector-componentlist'),
|
||
|
queryTb = componentList.down('#queryFieldTb'),
|
||
|
queryField = queryTb.down('#queryField');
|
||
|
|
||
|
tb.hide();
|
||
|
queryTb.show();
|
||
|
componentList.clearVMSearchIndicators();
|
||
|
queryField.setValue(queryField.lastValue);
|
||
|
componentList.filterComponentTree(null, queryField.lastValue);
|
||
|
}
|
||
|
}]
|
||
|
}];
|
||
|
|
||
|
me.callParent();
|
||
|
me.getView().on('itemdblclick', me.onItemDblclick, me);
|
||
|
me.on('select', me.onItemSelect, me);
|
||
|
|
||
|
// a quick-view tip to show the bindings for a given component
|
||
|
me.bindingsTip = Ext.create('Ext.tip.ToolTip', {
|
||
|
renderTo: document.body,
|
||
|
anchor: 'left',
|
||
|
cls: Ext.baseCSSPrefix + 'componentlist-tip',
|
||
|
bodyPadding: 12
|
||
|
});
|
||
|
|
||
|
// manually show the bindings tip on itemmouseenter
|
||
|
me.getView().on('itemmouseenter', me.showBindingsTip, me);
|
||
|
},
|
||
|
|
||
|
// the source VM indicators column which is shown during the Container.onVMSearchClick() call is then hidden
|
||
|
// between VM drill down searches
|
||
|
clearVMSearchIndicators: function () {
|
||
|
var indicatedVM = this.indicatedVM;
|
||
|
|
||
|
Ext.suspendLayouts();
|
||
|
if (indicatedVM) {
|
||
|
Ext.Array.forEach(indicatedVM, function (rec) {
|
||
|
rec.set('isSrcVM', false);
|
||
|
});
|
||
|
}
|
||
|
this.down('#srcVMIndicator').hide();
|
||
|
Ext.resumeLayouts(true);
|
||
|
|
||
|
this.indicatedVM = null;
|
||
|
},
|
||
|
|
||
|
// renderer for the source VM indicator column
|
||
|
srcVMIndicator: function (v, meta, rec) {
|
||
|
var refVM = rec.get('isSrcVM'),
|
||
|
tip = '',
|
||
|
vmDetail, firstTierRec, firstTierName, targetRec;
|
||
|
|
||
|
if (refVM) {
|
||
|
vmDetail = this.up('bindinspector-container').down('bindinspector-viewmodeldetail');
|
||
|
firstTierRec = vmDetail.getFirstTierRec(refVM);
|
||
|
firstTierName = firstTierRec.get('name');
|
||
|
if (firstTierRec !== refVM) {
|
||
|
tip += 'Root data node: <span class=\'' + Ext.baseCSSPrefix + 'binding-tip-descriptor\'>' + firstTierName + '</span><hr>';
|
||
|
}
|
||
|
|
||
|
targetRec = firstTierRec === refVM ? firstTierRec : refVM;
|
||
|
tip += targetRec.get('name') + ':';
|
||
|
tip += '<br> ';
|
||
|
tip += '<span class=\'' + Ext.baseCSSPrefix + 'binding-tip-value\'>' + Ext.app.bindinspector.Util.valueRenderer(targetRec.get('value')) + '</span>';
|
||
|
meta.tdCls = Ext.baseCSSPrefix + 'bindindicator-vm-src';
|
||
|
meta.tdAttr = 'data-qclass="' + Ext.baseCSSPrefix + 'componentlist-tip" data-qtip="' + tip + '"';
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// when the ComponentList is destroyed the stand-alone QuickTip needs to also be destroyed
|
||
|
onDestroy: function () {
|
||
|
this.bindingsTip.destroy();
|
||
|
this.callParent();
|
||
|
},
|
||
|
|
||
|
// when a nodeInterface / row is moused over show the bindings tooltip which will detail the specs > output value from the bindings on the component
|
||
|
showBindingsTip: function (view, record, item, index, e) {
|
||
|
var me = this,
|
||
|
tip = me.bindingsTip,
|
||
|
sansData = record.get('sansData'),
|
||
|
bindings, bindingText;
|
||
|
|
||
|
tip.stopAnimation();
|
||
|
if (record.get('hasBindings')) {
|
||
|
bindings = me.ownerCt.env.getCmp(record.get('id')).bindings;
|
||
|
bindingText = [];
|
||
|
|
||
|
// build the bindings markup for the tip
|
||
|
Ext.Object.each(bindings, function (key, val, o) {
|
||
|
var kv = key + ': ' + '<span class="' + Ext.baseCSSPrefix + 'binding-tip-descriptor">' + val.descriptor + '</span><br>',
|
||
|
bindValue = val.value,
|
||
|
v;
|
||
|
|
||
|
if (Ext.isString(bindValue)) {
|
||
|
v = bindValue;
|
||
|
} else if (Ext.isObject(bindValue)) {
|
||
|
if (bindValue.isStore === true) {
|
||
|
v = 'Store {' + bindValue.entityName + '}';
|
||
|
} else if (bindValue.isModel === true) {
|
||
|
v = 'Model {' + bindValue.entityName + '}';
|
||
|
}
|
||
|
}
|
||
|
kv += '<span class="' + Ext.baseCSSPrefix + 'binding-tip-value">' + v + '</span>';
|
||
|
bindingText.push(kv);
|
||
|
});
|
||
|
|
||
|
bindingText = bindingText.join('<hr>');
|
||
|
if (sansData) {
|
||
|
bindingText += '<hr>';
|
||
|
Ext.Array.forEach(sansData, function (missing) {
|
||
|
bindingText += '<div class="' + Ext.baseCSSPrefix + 'binding-missing-data">Missing data: ' + missing + '</div>';
|
||
|
});
|
||
|
}
|
||
|
tip.update(bindingText);
|
||
|
tip.setTarget(item);
|
||
|
tip.show();
|
||
|
tip.alignTo(item, 'l-r', [20, 0]);
|
||
|
tip.animate({
|
||
|
from: {
|
||
|
opacity: 0
|
||
|
},
|
||
|
to: {
|
||
|
opacity: 1,
|
||
|
x: tip.getX() - 10
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// filter for the component list (tree)
|
||
|
filterComponentTree: function (field, val) {
|
||
|
var tree = this,
|
||
|
field = tree.down('#queryField'),
|
||
|
newVal = val || field.getValue(),
|
||
|
store = tree.store,
|
||
|
queryRe = /[\s>\[\]=()^'"~$@*:+#,]/g,
|
||
|
valIsArray = Ext.isArray(newVal),
|
||
|
ids = valIsArray ? newVal : [],
|
||
|
components = [],
|
||
|
isQuery, len, i;
|
||
|
|
||
|
if (Ext.isString(newVal)) {
|
||
|
isQuery = queryRe.test(Ext.String.trim(newVal));
|
||
|
}
|
||
|
|
||
|
if (newVal.length > 0) {
|
||
|
tree.filteredComponents = [];
|
||
|
|
||
|
// if newVal matches the queryRe regex attempt the lookup using Ext.ComponentQuery
|
||
|
if (isQuery) {
|
||
|
try
|
||
|
{
|
||
|
components = Ext.ComponentQuery.query(newVal);
|
||
|
} catch (e) {}
|
||
|
|
||
|
len = components.length;
|
||
|
|
||
|
for (i = 0; i < len; i++) {
|
||
|
ids.push(components[i].id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
store.suspendEvents();
|
||
|
store.filter({
|
||
|
filterFn: function (node) {
|
||
|
var children = node.childNodes,
|
||
|
length = children && children.length,
|
||
|
visible = false,
|
||
|
j;
|
||
|
|
||
|
if (isQuery || valIsArray) {
|
||
|
visible = Ext.Array.contains(ids, node.get('id'));
|
||
|
} else {
|
||
|
visible = node.get('text').indexOf(newVal) > -1;
|
||
|
}
|
||
|
node.set('filtervisible', visible);
|
||
|
|
||
|
if (visible) {
|
||
|
tree.filteredComponents.push(node);
|
||
|
}
|
||
|
|
||
|
// check the child nodes to see if they are 'visible' and if so then show the parent node, too
|
||
|
for (j = 0; j < length; j++) {
|
||
|
if (children[j].get('visible')) {
|
||
|
visible = true;
|
||
|
}
|
||
|
}
|
||
|
return visible;
|
||
|
},
|
||
|
id: 'queryFilter'
|
||
|
});
|
||
|
store.resumeEvents();
|
||
|
tree.getView().refresh();
|
||
|
} else {
|
||
|
tree.clearComponentFilter();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// method to clear the filter from the component list (tree)
|
||
|
clearComponentFilter: function () {
|
||
|
var tree = this,
|
||
|
store = tree.store,
|
||
|
filtered = tree.filteredComponents || [],
|
||
|
len = filtered.length,
|
||
|
i = 0;
|
||
|
|
||
|
for (; i < len; i++) {
|
||
|
filtered[i].set('filtervisible', false);
|
||
|
}
|
||
|
store.clearFilter();
|
||
|
},
|
||
|
|
||
|
// constructs the tree node for the given component
|
||
|
buildNode: function(comp) {
|
||
|
var me = this,
|
||
|
ownerCt = me.getRefOwner(),
|
||
|
childItems = comp.items,
|
||
|
viewModel = comp.viewModel,
|
||
|
bindings = comp.bindings,
|
||
|
hasBindings = !!comp.bindings,
|
||
|
suffix = [],
|
||
|
sansData = [],
|
||
|
missing = {},
|
||
|
binding, len, i, o, child, ref, key, bindData;
|
||
|
|
||
|
if (viewModel) {
|
||
|
suffix.push('<span class="' + me.vmIconCls + '">' + me.vmIcon + '</span>');
|
||
|
ownerCt.buildVMDataMap(viewModel);
|
||
|
}
|
||
|
if (hasBindings) {
|
||
|
suffix.push('<span class="' + me.bindingsIconCls + '">' + me.bindingsIcon + '</span>');
|
||
|
|
||
|
for (key in bindings) {
|
||
|
binding = bindings[key];
|
||
|
if (binding.descriptor && Ext.isEmpty(binding.value)) {
|
||
|
sansData.push(missing[key] = binding.descriptor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bindData = comp.bindData = Ext.app.bindinspector.Util.buildBindData(bindings);
|
||
|
}
|
||
|
|
||
|
if (sansData.length === 0) {
|
||
|
sansData = undefined;
|
||
|
}
|
||
|
|
||
|
ref = comp.reference ? '<b>[' + comp.reference + ']</b> • ' : '';
|
||
|
|
||
|
o = {
|
||
|
id: comp.id,
|
||
|
text: ref + comp.id + (suffix.length ? (' ' + suffix.join(' ')) : ''),
|
||
|
hasViewModel: !!viewModel,
|
||
|
hasBindings: hasBindings,
|
||
|
hasDeepBindings: hasBindings,
|
||
|
reference: comp.reference,
|
||
|
sansData: sansData,
|
||
|
bindData: bindData,
|
||
|
children: []
|
||
|
};
|
||
|
|
||
|
if (childItems) {
|
||
|
for (i = 0, len = childItems.length; i < len; ++i) {
|
||
|
child = me.buildNode(childItems[i]);
|
||
|
o.hasDeepBindings = o.hasDeepBindings || child.hasDeepBindings;
|
||
|
if (child.hasDeepBindings) {
|
||
|
o.children.push(child);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (o.children.length) {
|
||
|
o.expanded = true;
|
||
|
o.leaf = false;
|
||
|
} else {
|
||
|
o.leaf = true;
|
||
|
}
|
||
|
|
||
|
return o;
|
||
|
},
|
||
|
|
||
|
// on item dblclick fire the 'componentdblclick' event for the bindinspector-container to listen for
|
||
|
onItemDblclick: function(view, rec) {
|
||
|
this.fireEvent('componentdblclick', this, rec);
|
||
|
},
|
||
|
|
||
|
// on item select fire the 'componentselect' event for the bindinspector-container to listen for
|
||
|
onItemSelect: function (selModel, rec) {
|
||
|
var node = this.getView().getNode(rec);
|
||
|
this.fireEvent('componentselect', this, rec, node);
|
||
|
}
|
||
|
}, function() {
|
||
|
this.prototype.Model = Ext.define(null, {
|
||
|
extend: 'Ext.data.TreeModel',
|
||
|
fields: ['hasViewModel', 'hasBindings', 'reference', 'hasDeepBindings', 'reference', 'sansData', 'bindData', 'isSrcVM']
|
||
|
});
|
||
|
});
|