/**
* CustomSet is a tool for creating a layout of other tools.
*
* @class CustomSet
* @memberof Tools
*/
Ext.define('Voyant.panel.CustomSet', {
extend: 'Ext.panel.Panel',
mixins: ['Voyant.panel.Panel'],
alias: 'widget.customset',
statics: {
i18n: {
},
api: {
/**
* @memberof Tools.CustomSet
* @instance
* @property {String} layout A border layout string, of the format expected by <a target="_blank" href="https://docs.sencha.com/extjs/6.2.0/classic/Ext.layout.container.Border.html">Border layout</a>
*/
layout: undefined,
/**
* @memberof Tools.CustomSet
* @instance
* @property {String} tableLayout A table layout string, usually generated by the <a target="_blank" href="https://voyant-tools.org/builder/">Skin Builder</a>
*/
tableLayout: undefined
},
glyph: 'xf17a@FontAwesome'
},
header: false,
height: '100%',
width: '100%',
constructor: function() {
this.mixins['Voyant.util.Api'].constructor.apply(this, arguments); // force api load
this.callParent(arguments);
this.mixins['Voyant.panel.Panel'].constructor.apply(this, arguments);
},
initComponent: function() {
if (this.getApiParam('layout')) {
Ext.apply(this,{
layout: 'border',
items: []
})
} else if (this.getApiParam('tableLayout')) {
this.initTableLayout();
}
this.callParent()
},
listeners: {
loadedCorpus: function(src, corpus) {
if (this.getApiParam('layout')) { // not sure why, but we seem to need to fire event for child panels
this.query("panel").forEach(function(p) {
p.fireEvent("loadedCorpus", src, corpus);
})
}
},
boxready: function(panel) {
if (this.getApiParam('layout')) {
this.initBorderLayoutComponents();
} else if (this.getApiParam('tableLayout')) {
this.doTableSizing();
this.on('resize', function(panel, newwidth, newheight, oldwidth, oldheight) {
if (oldwidth !== undefined && oldheight !== undefined) {
var widthRatio = newwidth/oldwidth;
var heightRatio = newheight/oldheight;
this.doTableSizing(widthRatio, heightRatio);
}
}, this);
} else {
this.showError(this.localize('noLayoutSpecified'))
}
}
},
initBorderLayoutComponents: function() {
var layoutString = decodeURI(this.getApiParam('layout'))
.replace(/r1/g, 'region')
.replace(/i1/g, 'items')
.replace(/s1/g, 'split')
.replace(/c1/g, 'collapsible')
.replace(/c2/g, 'collapsed')
.replace(/w1/g, 'width')
.replace(/h1/g, 'height')
.replace(/p1/g, '%')
.replace(/"x1":"/g, '"xtype":"')
.replace(/c3/g, 'center')
.replace(/n1/g, 'north')
.replace(/e1/g, 'east')
.replace(/s2/g, 'south')
.replace(/w2/g, 'west')
.replace(/"xtype":"(\w+)"/g, function(match, tool) {
if (!Ext.ClassManager.getByAlias("widget."+tool.toLowerCase())) {
if (tool=="Links") {tool="CollocatesGraph";}
else if (tool=="CorpusGrid") {tool="Documents";}
else if (tool=="CorpusSummary") {tool="Summary";}
else if (tool=="CorpusTypeFrequenciesGrid") {tool="CorpusTerms";}
else if (tool=="DocumentInputAdd") {tool="CorpusTerms";}
else if (tool=="DocumentTypeCollocateFrequenciesGrid") {tool="CorpusTerms";}
else if (tool=="DocumentTypeFrequenciesGrid") {tool="DocumentTerms";}
else if (tool=="DocumentTypeKwicsGrid") {tool="Contexts";}
else if (tool=="TypeFrequenciesChart") {tool="Trends";}
else if (tool=="VisualCollocator") {tool="CollocatesGraph";}
else {tool="NoTool"}
}
return '"xtype":"'+tool.toLowerCase()+'"'+(tool=="NoTool" ? ',"html":"'+new Ext.Template(panel.localize('noSuchTool')).applyTemplate([tool])+'"' : '')
})
var items;
try {
items = Ext.decode(layoutString);
} catch (e) {
items = {region: 'center', html: '<div>Error constructing layout:'+e+'</div>'};
}
if (items == null) {
items = {region: 'center', html: '<div>Error: no layout information found.</div>'}
}
this.addBorderLayouts(items);
this.on("add", function(custom, cmp) {
cmp.on("boxready", function(cmp) {
// cmp.query("panel").forEach(function(p) {
// custom;
//// debugger
// })
})
})
this.add(items);
// .on("boxready", function() {
// debugger
// if (this.getCorpus()) { // we may have loaded the corpus after the layout, so refire the event
// this.getApplication().dispatchEvent("loadedCorpus", this.getApplication(), corpus);
// }
// })
},
addBorderLayouts: function(items) {
var size = Ext.getBody().getSize();
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (Ext.isString(item.width)) {
item.width = Math.round(size.width * parseInt(item.width) / 100);
} else if (Ext.isString(item.height)) {
item.height = Math.round(size.height * parseInt(item.height) / 100);
}
if (item.items && item.items.length > 1) {
item.layout = 'border';
this.addBorderLayouts(item.items);
} else {
item.layout = 'fit';
}
}
},
initTableLayout: function() {
Ext.suspendLayouts();
var tableLayout = decodeURI(this.getApiParam('tableLayout'));
if (tableLayout && tableLayout.charAt(0)!="{" && tableLayout.charAt(0)!="[") {
var cells = [];
tableLayout.replace(/;/g,",").split(/,\s*/).forEach(function(cell) {
cells.push(/^"'/.test(cell) ? cell : '"'+cell+'"');
});
tableLayout = "["+cells.join(",")+"]"; // treat as simple comma-separated string
}
var layout = Ext.decode(tableLayout);
if (Ext.isArray(layout)) {
layout = {
cells: layout
};
}
if (!layout.numCols && layout.cells && Ext.isArray(layout.cells)) {
if (layout.cells.length < 3) {
layout.numCols = layout.cells.length;
} else if (layout.cells.length < 5) {
layout.numCols = Math.ceil(layout.cells.length / 2);
} else {
layout.numCols = Math.ceil(layout.cells.length / 3);
}
}
if (layout.numCols != null && layout.cells && Ext.isArray(layout.cells)) {
var items = [];
for (var i = 0; i < layout.cells.length; i++) {
var cell = layout.cells[i];
if (Ext.isObject(cell)) {
cell.cellWidth = parseFloat(cell.width) || undefined;
cell.cellHeight = parseFloat(cell.height) || undefined;
delete cell.width;
delete cell.height;
items.push(cell);
} else if (Ext.isArray(cell)) {
var colspan = 1, rowspan = 1; xtype = undefined;
if (cell[0] && Ext.isNumber(cell[0])) {
colspan = cell[0];
cell.shift();
}
if (cell[0] && Ext.isString(cell[0])) {
xtype = cell[0].toLowerCase();
cell.shift();
}
if (cell[0] && Ext.isNumber(cell[0])) {
rowspan = cell[0];
}
if (xtype) {
items.push({
colspan: colspan,
rowspan: rowspan,
xtype: xtype
})
}
} else if (Ext.isString(cell)) {
items.push({
xtype: cell.toLowerCase(),
colspan: 1,
rowspan: 1
})
}
}
Ext.apply(this, {
layout: {
type: 'table',
width: '100%',
height: '100%',
columns: layout.numCols,
tableAttrs: {
style: {
width: '100%',
height: '100%'
}
},
tdAttrs: {
style: {
padding: '0px',
verticalAlign: 'top'
}
}
},
defaults: { // place holder values to ensure that the children are rendered
width: 10,
height: 10,
border: true
},
items: items
});
} else {
this.showError("badTableLayoutDefinition")
}
Ext.resumeLayouts();
},
doTableSizing: function(widthRatio, heightRatio) {
var sizeMap = {};
var table = this.getTargetEl().down(".x-table-layout");
var tableSize = table.getSize(false);
var rows = table.dom.rows;
for (var i=0; i<rows.length; i++) {
var cells = rows[i].cells;
for (var j=0; j<cells.length; j++) {
var cell = cells[j];
var cellEl = Ext.get(cell);
var panelEl = cellEl.down('.x-panel');
var cmpId = panelEl.id;
var size;
if (widthRatio !== undefined && heightRatio !== undefined) {
size = panelEl.getSize(false);
size.width = size.width * widthRatio;
size.height = size.height * heightRatio;
// FIXME multiple resize calls gradually reduce size
} else {
var sizeObj = cellEl.getSize(false);
var cmp = Ext.getCmp(cmpId);
var widthPercent = cmp.initialConfig.cellWidth;
var heightPercent = cmp.initialConfig.cellHeight;
if (widthPercent !== undefined) {
sizeObj.width = tableSize.width * (widthPercent/100);
cellEl.setWidth(sizeObj.width);
}
if (heightPercent !== undefined) {
sizeObj.height = tableSize.height * (heightPercent/100);
cellEl.setHeight(sizeObj.height);
}
size = sizeObj;
}
sizeMap[cmpId] = size;
}
}
for (var id in sizeMap) {
var size = sizeMap[id];
Ext.getCmp(id).setSize(size);
}
this.updateLayout();
}
})