@domoinc/domo-select
Version:
DomoSelect - Domo Widget
446 lines (415 loc) • 13.6 kB
JavaScript
var d3 = require('d3');
var d3Chart = require('d3.chart');
var BaseWidget = require('@domoinc/base-widget');
var Dropdown = require('@domoinc/dropdown');
var Button = require('@domoinc/button');
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
// DomoSelect:
// This is where you can give some high level documentation of your widget.
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
module.exports = BaseWidget.extend('DomoSelect', {
//**********************************************************************************
// Anything in the initialization method will only run once.
// i.e. It will not be run every time you call draw.
//**********************************************************************************
initialize: function() {
// Make the chart constructor accessible to all other methods.
var _Chart = this;
var _selectedValue;
_Chart.transform = processData;
this._newConfig = {
//Plugin configurable configs
width: {
name: 'Widget Width',
description: 'Width of the widget',
value: 250,
type: 'number',
units: 'px'
},
size: {
description: 'Size of the button and the dropdown',
type: 'string',
value: 'small',
},
centerText: {
name: 'Text Position',
description: 'Set the text position',
type: 'select',
value: { name: 'Left', value: false },
options: [
{ name: 'Left', value: false },
{ name: 'Center', value: true },
]
},
color: {
description: 'Color of the dropdown button',
type: 'string',
value: 'lightGrey',
onChange: function(val) {
var theme;
switch (val) {
case 'clear':
theme = 'thm-clear';
break;
case 'lightGrey':
theme = 'thm-light-grey';
break;
case 'lightGreyInvert':
theme = 'thm-light-grey-invert';
break;
case 'none':
theme = 'thm-none';
break;
case 'darkGrey':
theme = 'thm-dark-grey';
break;
case 'orange':
theme = 'thm-orange';
break;
case 'orangeInvert':
theme = 'thm-orange-invert';
break;
case 'green':
theme = 'thm-green';
break;
case 'greenInvert':
theme = 'thm-green-invert';
break;
case 'red':
theme = 'thm-red';
break;
case 'redInvert':
theme = 'thm-red-invert';
break;
default:
theme = val;
break;
}
_Chart.button.c({ theme: theme })
}
},
initialIndex: {
name: 'Initial Selection',
description: 'Sets the default option to show on the select bar (the number corresponds to the options\' order number in the dropdown)',
type: 'number',
value: 0,
},
domoScroll: {
name: 'Show Scroll Bar',
description: 'Shows the scroll bar to the right of the dropdown',
type: 'select',
value: { name: 'Hide', value: false },
options: [
{ name: 'Show', value: true },
{ name: 'Hide', value: false },
]
},
//widget default configs
chartName: {
description: 'Name of chart for reporting',
type: 'string',
value: 'Dropdown'
},
height: {
description: 'Height of the select',
type: 'string',
value: '250px',
},
marginBottom: {
description: 'Margin Bottom',
type: 'string',
value: '0px'
},
listIconPadding: {
description: 'Left padding on the dropdown',
type: 'number',
value: 0,
},
staticValue: {
description: 'Sets a static default value on the select',
type: 'string',
value: null
},
dropdownLocation: {
description: 'Direction that the dropdown extends from',
type: 'string',
value: 'bottom'
},
orientation: {
description: 'Orientation of the button',
type: 'string',
value: 'horizontal',
},
popoutHeight: {
description: 'Height of the dropdown when opened',
type: 'number',
value: '250px',
},
buttonIcon: {
description: 'd3 selection of the element for the button icon',
type: 'd3 selection',
value: null
},
listIconFunction: {
description: 'Function to run on each dropdown list item for icons.',
type: 'function',
value: function() {}
},
disabled: {
description: 'Disables the dropdown',
type: 'boolean',
value: false,
}
};
// Update config object from base chart.
this.mergeConfig(_Chart._newConfig);
//----------------------------------------------------------------------------------
// Accessor Functions:
// Set functions on how to access data values
//----------------------------------------------------------------------------------
_Chart._newDataDefinition = {
'Label': {
type: 'string',
validate: function(d) {
return this.accessor(d) !== 'undefined';
},
accessor: function(line) {
return String(line[0]);
},
},
'Value': {
type: 'string',
validate: function(d) {
return this.accessor(d) !== 'undefined';
},
accessor: function(line) {
return String(line[1]);
},
}
};
// Update data defs object from base chart.
this.mergeDataDefinition(_Chart._newDataDefinition);
_Chart.widgetContainer = this._layerGroup
.attr('class', 'da-domo-select');
// Add button to widget
_Chart.button = this.widgetContainer
.chart('Button')
.c('theme', 'thm-light-grey')
// Add dropdown to widget
_Chart.dropdown = this.widgetContainer
.chart('Dropdown');
// Attach charts to _Chart object
this.attach('button', _Chart.button);
this.attach('dropdown', _Chart.dropdown);
_Chart._dropdownOpen = _Chart.dropdown.c('visible');
// Click event handles
_Chart.button.on('dispatch:click', function(d) {
displayDropdown();
_Chart.dropdown.toggleVisibility();
_Chart._dropdownOpen = _Chart.dropdown.c('visible');
})
.on('dispatch:focusout', function() {
if (_Chart._dropdownOpen) {
_Chart._dropdownOpen = false;
setTimeout(function() {
_Chart.dropdown.toggleVisibility();
}, 250)
}
})
.on('dispatch:blur', function() {
if (_Chart._dropdownOpen) {
_Chart._dropdownOpen = false;
setTimeout(function() {
_Chart.dropdown.toggleVisibility();
}, 250)
}
})
_Chart.dropdown.on('click', function(d, i) {
if (!_Chart.c('staticValue')) {
_Chart.button.c('textElement')
.text(_Chart.a('Label')(d))
}
_Chart.trigger('valueSelected', d, i);
_selectedValue = d;
_Chart.trigger('dispatch:selection', { data: _selectedValue });
});
//************************************************
//Puts the dropdown where it needs to go on click
//************************************************
function displayDropdown() {
var dropdownStyle = {};
var boxShadow = 3;
var padding = 7;
var containerBBox = _Chart.base.node().getBoundingClientRect();
var dropdownBBox = _Chart.dropdown.dropdownContainer.node().getBoundingClientRect();
var buttonBBox = _Chart._layerGroup.select('.da-btn').node().getBoundingClientRect();
var marginLeft = buttonBBox.left - containerBBox.left;
var marginTop = buttonBBox.top - containerBBox.top;
switch (_Chart.c('dropdownLocation')) {
// switch(_Chart.c('dropdownLocation').value) {
case 'bottom':
dropdownStyle.display = 'list-item'
break;
case 'top':
dropdownStyle.top = (marginTop - padding) + (-dropdownBBox.height - (boxShadow * 2) - padding) + 'px'
break;
case 'right':
dropdownStyle.left = marginLeft + (buttonBBox.width + (boxShadow * 2) + padding) + 'px'
dropdownStyle.top = marginTop + -(boxShadow * 2) + 'px'
break;
case 'left':
dropdownStyle.right = marginLeft + (buttonBBox.width + (boxShadow * 2) + padding) + 'px'
dropdownStyle.top = marginTop + -(boxShadow * 2) + 'px'
break;
}
_Chart.dropdown.dropdownContainer.style(dropdownStyle)
}
//**********************************************************************************
// processData: Called before dataBind on the layers
// the data returned is passed into dataBind.
//**********************************************************************************
function processData(onDrawData) {
if (_Chart.c('width') < 50) {
_Chart.c('width', 50);
}
//find size abbreviation for corresponding small, medium, and large values
var buttonSize;
if (_Chart.c('size') === 'small') {
buttonSize = 'sz-sm';
} else if (_Chart.c('size') === 'medium') {
buttonSize = 'sz-md';
} else if (_Chart.c('size') === 'large') {
buttonSize = 'sz-lg';
}
// Set properties of the dropdown based off this charts config
_Chart.dropdown.c({
width: _Chart.c('width'),
height: _Chart.c('popoutHeight'),
size: _Chart.c('size'),
visible: false,
selectedIndex: _Chart.c('initialIndex'),
domoScroll: !_Chart.c('domoScroll').value,
listIconFunction: _Chart.c('listIconFunction'),
listIconPadding: _Chart.c('listIconPadding'),
}).a({
Label: _Chart.a('Label'),
Value: _Chart.a('Value')
})
// Set properties of the button based off this charts config
_Chart.button.c({
width: _Chart.c('width'),
size: buttonSize,
orientation: _Chart.c('orientation'),
centerText: _Chart.c('centerText').value,
selectedIndex: _Chart.c('initialIndex'),
showChevron: true,
disabled: _Chart.c('disabled'),
staticValue: _Chart.c('staticValue')
}).a({
Label: _Chart.a('Label')
})
if (_Chart.c('staticValue')) {
_Chart.button.c('textElement').text(_Chart.c('staticValue'));
} else if (onDrawData && _Chart.c('initialIndex') < onDrawData.length && _Chart.c('initialIndex') > -1) {
_selectedValue = onDrawData[_Chart.c('initialIndex')];
_Chart.button.c('textElement').text(_Chart.a('Label')(_selectedValue))
}
_Chart.c('buttonIcon', _Chart.button.c('leftIconElement'));
_Chart.widgetContainer.style({
'margin-bottom': _Chart.c('marginBottom')
});
return onDrawData;
}
_Chart.reset = function() {
_Chart.dropdown.setSelectedValueByIndex(_Chart.c('initialIndex'));
};
_Chart.setSelectedValue = function(label) {
_Chart.dropdown.setSelectedValueByLabel(label);
};
_Chart.getSelectedValue = function() {
return _selectedValue;
};
},
//************************************************
//Legacy Getter/Setters for backwards compatibility
//************************************************
disabled: function(_) {
if (arguments.length === 0) {
return this.c('disabled');
}
this.c('disabled', _);
return this;
},
marginBottom: function(_) {
if (arguments.length === 0) {
return this.c('marginBottom');
}
this.c('marginBottom', _);
return this;
},
width: function(_) {
if (arguments.length === 0) {
return this.c('width');
}
this.c('width', _)
return this;
},
popoutHeight: function(_) {
if (arguments.length === 0) {
return this.c('popoutHeight');
}
this.c('popoutHeight', _);
return this;
},
size: function(_) {
if (arguments.length === 0) {
return this.c('size');
}
this.c('size', _);
return this;
},
color: function(_) {
if (arguments.length === 0) {
return this.c('color');
}
this.c('color', _);
return this;
},
center: function(_) {
if (arguments.length === 0) {
return this.c('centerText');
}
this.c('centerText', _);
return this;
},
orientation: function(_) {
if (arguments.length === 0) {
return this.c('orientation');
}
this.c('orientation', _);
return this;
},
dropdownLocation: function(_) {
if (arguments.length === 0) {
return this.c('dropdownLocation');
}
this.c('dropdownLocation', _);
return this;
},
staticValue: function(_) {
if (arguments.length === 0) {
return this.c('staticValue');
}
this.c('staticValue', _);
return this;
},
initialIndex: function(_) {
if (arguments.length === 0) {
return this.c('initialIndex');
}
this.c('initialIndex', _);
return this;
}
});