define([
|
'require',
|
'dojo/_base/array',
|
'dojo/_base/declare',
|
'dojo/_base/lang',
|
'dojo/dom-class',
|
'dojo/query',
|
'dojo/string',
|
'dojo/on',
|
'dojo/topic',
|
'dijit/_WidgetBase',
|
'dijit/_TemplatedMixin',
|
'dijit/_WidgetsInTemplateMixin',
|
'dijit/form/TextBox',
|
'dijit/form/SimpleTextarea',
|
'dstore/Memory',
|
'dstore/Trackable',
|
'dstore/Tree',
|
'./aboutDialog',
|
'./ColumnEditor',
|
'./FeatureEditor',
|
'../util/toJavaScript',
|
'../data/config',
|
'dojo/i18n!../nls/laboratory',
|
'dojo/text!./templates/Laboratory.html',
|
'dojo/text!./templates/gridCode.js',
|
'dojo/query',
|
// Widgets in template
|
'dijit/layout/ContentPane',
|
'dijit/layout/TabContainer'
|
], function (require, arrayUtil, declare, lang, domClass, query, string, on, topic,
|
_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, TextBox, SimpleTextarea,
|
Memory, Trackable, TreeStoreMixin, aboutDialog, ColumnEditor, FeatureEditor,
|
toJavaScript, config, i18n, template, codeTemplate) {
|
|
var NUM_ITEMS = 50;
|
var dijitNameToConstructor = {
|
TextBox: TextBox,
|
SimpleTextarea: SimpleTextarea
|
};
|
|
return declare([ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin ], {
|
templateString: template,
|
i18n: i18n,
|
docBaseUrl: config.docBaseUrl,
|
dgridUrl: config.dgridUrl,
|
|
// resourcesBaseUrl is used for image paths; toUrl includes cacheBust so strip it
|
resourcesBaseUrl: require.toUrl('../resources').replace(/\?.*$/, ''),
|
|
baseClass: 'laboratory',
|
|
aboutVisible: true,
|
aboutKey: '', // Passed from index.html if localStorage is supported
|
|
buildRendering: function () {
|
this.inherited(arguments);
|
|
this.featureEditor = new FeatureEditor({}, this.featureEditorNode);
|
this.columnEditor = new ColumnEditor({}, this.columnEditorNode);
|
},
|
|
postCreate: function () {
|
this.inherited(arguments);
|
|
this.own(
|
topic.subscribe('/configuration/changed', lang.hitch(this, '_updateDemo'))
|
// this.previewTabs.watch('selectedChildWidget', lang.hitch(this, '_updateDemo'))
|
);
|
|
this._selectedChildWidget = this.demoGridPane;
|
},
|
|
startup: function () {
|
var columnEditor = this.columnEditor;
|
this.inherited(arguments);
|
|
this.featureEditor.startup().then(function () {
|
columnEditor.startup();
|
|
// Add a couple of columns by default;
|
// wait until after FeatureEditor's startup promise resolves,
|
// to give forms a chance to react to column addition/removal (e.g. Tree)
|
columnEditor.addColumn('First Name');
|
columnEditor.addColumn('Last Name');
|
});
|
},
|
|
selectTab: function (evt) {
|
var target = evt.target.getAttribute('data-target');
|
query('.active', this.domNode).removeClass('active');
|
|
query('[data-target="' + target + '"]', this.domNode).addClass('active');
|
if (target !== 'columns') {
|
// The Grid and Column Features "tabs" actually both show the same widget,
|
// but using a different filter for its grid
|
this.featureEditor.set('featureType', (target === 'gridFeatures') ? 'grid' : 'column');
|
target = 'features';
|
}
|
query('[data-tab="' + target + '"]', this.domNode).addClass('active');
|
},
|
|
_showAbout: function (event) {
|
event.preventDefault();
|
aboutDialog.show();
|
},
|
|
_toggleColumns: function () {
|
domClass.toggle(this.columnEditorNode, 'open');
|
},
|
|
_updateDemo: function () {
|
if (this.demoGrid) {
|
this.demoGrid.destroy();
|
}
|
|
this.gridCodeTextArea.value = '';
|
|
// If no columns have been defined, then don't bother rendering an empty demo grid
|
// or generating code for an empty grid
|
if (this.columnEditor.get('columns').length < 1) {
|
return;
|
}
|
|
if (this._selectedChildWidget === this.demoGridPane) {
|
this._showDemoGrid();
|
}
|
else {
|
this._showCode();
|
}
|
},
|
|
_selectCode: function () {
|
this._selectedChildWidget = this.demoCodePane;
|
this.previewTabs.setAttribute('data-selected-page', 'code');
|
this._updateDemo();
|
},
|
|
_selectGrid: function () {
|
this._selectedChildWidget = this.demoGridPane;
|
this.previewTabs.setAttribute('data-selected-page', 'grid');
|
this._updateDemo();
|
},
|
|
_showCode: function () {
|
this.gridCodeTextArea.value = this._generateCode();
|
},
|
|
_generateCode: function () {
|
var gridConfig = {
|
gridOptions: '{\n',
|
dataDeclaration: '',
|
dataCreation: '',
|
gridRender: ''
|
};
|
// deps, prams, and grid modules are built as arrays then joined when assigned to gridConfig
|
var dependencies = [ 'dojo/_base/declare' ];
|
var callbackParams = [ 'declare' ];
|
var gridModules = [];
|
var gridOptions = this._generateGridOptions();
|
var columnNames = [];
|
var columnName;
|
var treeExpandoColumn;
|
var storeModules;
|
var hasStore = this.featureEditor.isSelected('dgrid/OnDemandGrid') ||
|
this.featureEditor.isSelected('dgrid/extensions/Pagination');
|
|
arrayUtil.forEach(this.columnEditor.get('columns'), function (columnConfig) {
|
// Convert any dijit module IDs for column.editor to constructors, and add the necessary dependencies
|
var formWidgetCallbackParam = toJavaScript.formatDijitFormWidget(columnConfig.editor);
|
if (formWidgetCallbackParam && callbackParams.indexOf(formWidgetCallbackParam) < 0) {
|
dependencies.push(columnConfig.editor);
|
callbackParams.push(formWidgetCallbackParam);
|
}
|
}, this);
|
// The expandoColumn for Tree is a special case:
|
// In the UI, it works better to present it in the grid feature config,
|
// although it's really a column config option. In order to add it to the appropriate column config
|
// we need to get its value
|
if (this.featureEditor.isSelected('dgrid/Tree')) {
|
treeExpandoColumn = this.featureEditor.get('expandoColumn');
|
}
|
|
if (hasStore) {
|
storeModules = [ 'Memory', 'Trackable' ];
|
|
if (treeExpandoColumn) {
|
storeModules.push('TreeStoreMixin');
|
}
|
|
gridConfig.dataDeclaration = 'var store = new (declare([' + storeModules.join(', ') + ']))({\n' +
|
'\t\tdata: createData()\n\t});';
|
}
|
else {
|
gridConfig.dataDeclaration = 'var data = createData();';
|
}
|
|
for (columnName in gridOptions.columns) {
|
columnNames.push(toJavaScript.formatPropertyName(columnName));
|
}
|
|
gridConfig.dataCreation = '\n\n\tfunction createData() {' +
|
'\n\t\tvar data = [];' +
|
'\n\t\tvar column;' +
|
'\n\t\tvar i;' +
|
'\n\t\tvar item;' + '\n' +
|
'\n\t\tfor (i = 0; i < ' + NUM_ITEMS + '; i++) {' +
|
'\n\t\t\titem = {};' +
|
'\n\t\t\tfor (column in { ' + columnNames.join(': 1, ') + ': 1 }) {' +
|
'\n\t\t\t\titem.id = i;' +
|
'\n\t\t\t\titem[column] = column + \'_\' + (i + 1);' +
|
'\n\t\t\t}';
|
|
if (treeExpandoColumn) {
|
gridConfig.dataCreation += '\n\t\t\tif (i > 1) {';
|
gridConfig.dataCreation += '\n\t\t\t\titem.hasChildren = false;';
|
gridConfig.dataCreation += '\n\t\t\t\titem.parent = i % 2;';
|
gridConfig.dataCreation += '\n\t\t\t}';
|
}
|
|
gridConfig.dataCreation += '\n\t\t\tdata.push(item);' +
|
'\n\t\t}' + '\n' +
|
'\n\t\treturn data;' +
|
'\n\t}';
|
|
if (hasStore) {
|
dependencies.push('dstore/Memory', 'dstore/Trackable');
|
callbackParams.push('Memory', 'Trackable');
|
|
if (treeExpandoColumn) {
|
dependencies.push('dstore/Tree');
|
callbackParams.push('TreeStoreMixin');
|
}
|
|
gridConfig.storeDeclaration = '\n\tvar store = new (declare([ Memory, Trackable ]))({\n' +
|
'\t\tdata: data\n\t});\n';
|
gridConfig.storeAssignment = '\n\tgrid.set(\'collection\', store);';
|
}
|
else {
|
gridConfig.gridRender = '\n\tgrid.renderArray(data);';
|
}
|
|
// Add selected items from the feature store to the dependency list
|
arrayUtil.forEach(this.featureEditor.filter({ selected: true }), function (item) {
|
// Configuration for dgrid/Grid is always available since it is the base clase for OnDemandGrid
|
// If OnDemandGrid is selected then we can skip adding dgrid/Grid to the dependencies
|
if (item.mid === 'dgrid/Grid' && this.featureEditor.isSelected('dgrid/OnDemandGrid')) {
|
return;
|
}
|
|
var moduleReference = item.mid.slice(item.mid.lastIndexOf('/') + 1);
|
|
dependencies.push(item.mid);
|
callbackParams.push(moduleReference);
|
gridModules.push(moduleReference);
|
}, this);
|
|
if (hasStore) {
|
gridConfig.gridOptions += '\t\tcollection: store,\n';
|
}
|
|
gridConfig.gridOptions += toJavaScript(gridOptions, { indent: 1, inline: true } );
|
gridConfig.gridOptions += '\n\t}';
|
|
gridConfig.dependencies = '\'' + dependencies.join('\',\n\t\'') + '\'';
|
gridConfig.callbackParams = callbackParams.join(', ');
|
gridConfig.gridModules = gridModules.join(', ');
|
|
return string.substitute(codeTemplate, gridConfig);
|
},
|
|
_showDemoGrid: function () {
|
var self = this;
|
var gridOptions = this._generateGridOptions();
|
var gridModules = [];
|
var isTree = this.featureEditor.isSelected('dgrid/Tree');
|
var data = this._generateMockData();
|
var hasStore = this.featureEditor.isSelected('dgrid/OnDemandGrid') ||
|
this.featureEditor.isSelected('dgrid/extensions/Pagination');
|
|
arrayUtil.forEach(this.featureEditor.filter({ selected: true }), function (item) {
|
// Configuration for dgrid/Grid is always available since it is the base clase for OnDemandGrid
|
// If OnDemandGrid is selected then we can skip adding dgrid/Grid to the dependencies
|
if (item.mid === 'dgrid/Grid' && this.featureEditor.isSelected('dgrid/OnDemandGrid')) {
|
return;
|
}
|
|
gridModules.push(item.mid);
|
}, this);
|
|
this._fixDijitConstructors(gridOptions.columns);
|
require(gridModules, function () {
|
var storeModules;
|
var store;
|
|
gridOptions.className = 'demoGrid';
|
|
if (hasStore) {
|
storeModules = [ Memory, Trackable ];
|
|
if (isTree) {
|
storeModules.push(TreeStoreMixin);
|
}
|
|
store = new (declare(storeModules))({
|
data: data
|
});
|
|
gridOptions.collection = isTree ? store.filter('mayHaveChildren') : store;
|
}
|
|
self.demoGrid = new (declare(Array.prototype.slice.apply(arguments)))(gridOptions);
|
self.demoGridPane.innerHTML = '';
|
self.demoGridPane.appendChild(self.demoGrid.domNode);
|
self.demoGrid.startup();
|
|
if (!hasStore) {
|
self.demoGrid.renderArray(data);
|
}
|
});
|
},
|
|
_generateGridOptions: function () {
|
var gridOptions = {};
|
var selectedFeatures = this.featureEditor.filter({ selected: true, configLevel: 'grid' });
|
var treeExpandoColumn;
|
var columns = [];
|
var column;
|
var tempColumns;
|
var numFieldName;
|
|
if (this.featureEditor.isSelected('dgrid/Tree')) {
|
treeExpandoColumn = this.featureEditor.get('expandoColumn');
|
}
|
|
arrayUtil.forEach(selectedFeatures, function (feature) {
|
var moduleConfig = this.featureEditor.getModuleConfig(feature.mid);
|
|
if (moduleConfig) {
|
lang.mixin(gridOptions, moduleConfig);
|
}
|
}, this);
|
|
arrayUtil.forEach(this.columnEditor.get('columns'), function (columnConfig) {
|
var config = this._fixDataTypes(lang.clone(columnConfig));
|
|
// The laboratory needs the store items to have a unique id property,
|
// but we don't want to include it in our output
|
delete config.id;
|
|
if (config.field === treeExpandoColumn) {
|
config.renderExpando = true;
|
}
|
numFieldName = numFieldName || isFinite(config.field);
|
columns.push(config);
|
}, this);
|
|
if (!numFieldName) {
|
// If there are no field names that are numbers, then use an object to define the columns.
|
tempColumns = {};
|
while ((column = columns.shift())) {
|
tempColumns[column.field] = column;
|
delete column.field;
|
}
|
columns = tempColumns;
|
}
|
|
if (this.featureEditor.isSelected('dgrid/ColumnSet')) {
|
gridOptions.columnSets = [[columns]];
|
}
|
else {
|
gridOptions.columns = columns;
|
}
|
|
return gridOptions;
|
},
|
|
// Fix data types on objects created from widget values
|
// Change string 'true'/'false' values to booleans
|
_fixDataTypes: function (obj) {
|
var propertyName;
|
|
if (typeof obj !== 'object') {
|
return obj;
|
}
|
|
for (propertyName in obj) {
|
if (obj[propertyName] === 'true') {
|
obj[propertyName] = true;
|
}
|
else if(obj[propertyName] === 'false') {
|
obj[propertyName] = false;
|
}
|
}
|
|
return obj;
|
},
|
|
_generateMockData: function () {
|
var mockData = [];
|
var fieldNames = [];
|
var i;
|
|
arrayUtil.forEach(this.columnEditor.get('columns'), function (columnConfig) {
|
fieldNames.push(columnConfig.field);
|
});
|
|
if (fieldNames.length > 0) {
|
for (i = 0; i < NUM_ITEMS; i++) {
|
mockData.push({});
|
mockData[i].id = i;
|
|
if (i > 1) {
|
mockData[i].hasChildren = false;
|
mockData[i].parent = i % 2;
|
}
|
|
arrayUtil.forEach(fieldNames, function (fieldName) {
|
mockData[i][fieldName] = fieldName + '_' + (i + 1);
|
});
|
}
|
}
|
|
return mockData;
|
},
|
|
_fixDijitConstructors: function(obj) {
|
if (obj) {
|
for (var columnKey in obj) {
|
var column = obj[columnKey];
|
if (column && column.editor) {
|
var dijitConstructorName = toJavaScript.formatDijitFormWidget(column.editor);
|
if (dijitConstructorName) {
|
column.editor = dijitNameToConstructor[dijitConstructorName];
|
}
|
}
|
}
|
}
|
}
|
});
|
});
|