UNPKG

@domoinc/domo-select

Version:

DomoSelect - Domo Widget

889 lines (773 loc) 29.4 kB
/*! Copyright 2016 Domo Inc. */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("d3"), require("d3.chart"), require("@domoinc/utilities"), require("@domoinc/base-widget")); else if(typeof define === 'function' && define.amd) define(["d3", "d3.chart", "utilities", "base-widget"], factory); else if(typeof exports === 'object') exports["Dropdown"] = factory(require("d3"), require("d3.chart"), require("@domoinc/utilities"), require("@domoinc/base-widget")); else root["Dropdown"] = factory(root["d3"], root["d3.chart"], root["da"], root["BaseWidget"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_3__, __WEBPACK_EXTERNAL_MODULE_4__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = "/dist/"; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { var d3 = __webpack_require__(1); var d3Chart = __webpack_require__(2); var Utilities = __webpack_require__(3); var BaseWidget = __webpack_require__(4); __webpack_require__(5); //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- // Dropdown: // This is where you can give some high level documentation of your widget. //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- module.exports = BaseWidget.extend('Dropdown', { //********************************************************************************** // 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; _Chart.transform = function(data) { if (!data || data.length === 0) { _Chart.noResults = true; data = [['No Results']]; } else { _Chart.noResults = false; } _Chart.updateConfigs(); _Chart.validateInitialIndex(data); _Chart.dropdownContainer .style({ 'display': function() { if (_Chart.c('visible')) { _Chart.setScrollDimensions(); return 'block'; } else { return 'none'; } } }) .transition() .style({ 'opacity': function() { if (_Chart.c('visible')) { return 1; } else { return 0; } } }); _Chart.dropdownContainer .classed('domoScroll', _Chart.c('domoScroll')); _Chart.setScrollDimensions(); if (data.length >= (_Chart.c('selectedIndex') + 1)) { _Chart.c('selectedValue', _Chart.a('Value')(data[_Chart.c('selectedIndex')])) } else { _Chart.c('selectedValue', _Chart.a('Value')(data[0])) } return data; }; this._newConfig = { chartName: { description: 'Name of chart for Reporting.', type: 'string', value: 'Dropdown' }, visible: { description: 'Show/Hide the dropdown.', type: 'boolean', value: true }, selectedIndex: { description: 'Selected Index', type: 'number', value: 0 }, selectedValue: { description: 'selectedValue', type: 'string', value: 'ConfigValue' }, size: { description: 'Size of the dropdown.', type: 'string', value: 'medium', }, domoScroll: { description: 'Turn on domo Scroll?', type: 'boolean', value: false, }, width: { description: 'Width of the dropdown', type: 'string', value: '250px', }, height: { description: 'Max Height of the dropdown', type: 'string', value: '200px', }, listIconFunction: { description: 'Function that runs on every list element', type: 'function', value: function() {} }, listIconPadding: { description: 'Padding for the list icons', type: 'number', value: 0 } }; // Update config object from base chart. this.mergeConfig(_Chart._newConfig); _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); //---------------------------------------------------------------------------------- // Interface - This is where you document your events. The chart's .on()' and // '.trigger()' methods will go here. //---------------------------------------------------------------------------------- _Chart.on('visibility', _Chart.toggleVisibility) //---------------------------------------------------------------------------------- // Static - Anything that is defined here will never change //---------------------------------------------------------------------------------- _Chart.dropdownContainer = _Chart._layerGroup .classed('da-dropdown', true); _Chart._dropdownGroup = _Chart.dropdownContainer.append("ul") .classed('dropdownList', true); _Chart.scroll = d3.scroll(); //---------------------------------------------------------------------------------- // Layers: This is where you'll place your layers. //---------------------------------------------------------------------------------- //********************************************************************************** //Place a small description of the layer here. //********************************************************************************** _Chart.layer('layer', this.dropdownContainer, { //********************************************************************************** // The 'this' context is the selection passed into layer. // You must return a d3 selection bound with data. //********************************************************************************** dataBind: function(data) { return _Chart._dropdownGroup.selectAll('li').data(data); }, //********************************************************************************** // The 'this' context is the 'enter()' selection. // Appends all elements w/o any style, attr, or on function calls. //********************************************************************************** insert: function() { var listElements = this.append('li') .classed('dropdownItem', true); if (!_Chart.noResults) { listElements.append('div') .classed('listItemIcon', true); } listElements.append('div') .classed('dropdownItemContainer', true) .style('pointer-events', 'none'); return listElements; }, //---------------------------------------------------------------------------------- // Element Life Cycle Events //---------------------------------------------------------------------------------- events: { //********************************************************************************** // The 'this' context is also the 'enter()' selection. // You can use this to append styles and attributes to inserted elements. //********************************************************************************** 'enter': function() { this.on('click', function(d, i) { _Chart.c('selectedIndex', i); _Chart.c('selectedValue', _Chart.a('Value')(d)); // Trigger click and pass data, allowing use to handle selecting element how they want _Chart.trigger('click', d, i); _Chart._dropdownGroup.selectAll('.active').classed('active', false); d3.select(this).classed('active', true); }); return this; }, //********************************************************************************** // This is the selection returned from the dataBind method. It's the selection // that contains all (existing and newly bound) elements. //********************************************************************************** 'merge': function() { this.classed('active', function(d, i) { if (_Chart.noResults) { return false; } else { return i === Number(_Chart.c('selectedIndex')) ? true : false; } }) this.classed('disabled', _Chart.noResults) this.select("div.dropdownItemContainer") .text(function(d) { return _Chart.a('Label')(d); }); if (_Chart.c('domoScroll')) { _Chart.scroll.resize(); } if (!_Chart.noResults) { this.select('.listItemIcon').call(function() { this.each(function(d, i) { var s = d3.select(this); _Chart.c('listIconFunction')(s, d, i); _Chart.reCalcIconPadding(s, _Chart.c('listIconPadding')) }) }) } return this; }, //********************************************************************************** // The 'this' context is the exit() selection. //********************************************************************************** 'exit': function() { if (_Chart.c('domoScroll')) { _Chart.scroll({ x: 0, y: 0 }); } return this.remove(); } }, }); _Chart.updateConfigs = function() { //size switch(_Chart.c('size')) { case 'small': _Chart.dropdownContainer.classed('dd-sm', true); _Chart.dropdownContainer.classed('dd-md', false); _Chart.dropdownContainer.classed('dd-lg', false); break; case 'large': _Chart.dropdownContainer.classed('dd-sm', false); _Chart.dropdownContainer.classed('dd-md', false); _Chart.dropdownContainer.classed('dd-lg', true); break; default: _Chart.dropdownContainer.classed('dd-sm', false); _Chart.dropdownContainer.classed('dd-md', true); _Chart.dropdownContainer.classed('dd-lg', false); } //domoScroll if (!_Chart.c('domoScroll')) { _Chart.dropdownContainer .classed('domoScroll', false); _Chart.scroll({ x: 0, y: 0 }); _Chart._dropdownGroup.on('wheel', function() { return }); _Chart._dropdownGroup.on('mousewheel', function() { return }); } //width var width = parseInt(_Chart.c('width')) - 8; width = width < 0 ? 0 : width; _Chart.dropdownContainer.style({ 'width': width + 'px', 'margin-left': '3px' }); //height var height = _Chart.c('height'); if (typeof height === 'number') { height = height + 'px'; } _Chart.dropdownContainer.style({ 'max-height': height }) } /** * ensure the initial index is within the range of the data length */ _Chart.validateInitialIndex = function(data) { if (_Chart.c('selectedIndex') < 0) { _Chart.c('selectedIndex', 0); return; } else if (_Chart.c('selectedIndex') > data.length - 1) { _Chart.c('selectedIndex', data.length - 1); return; } return; } _Chart.toggleVisibility = function() { _Chart.c('visible', !_Chart.c('visible')); _Chart.dropdownContainer .style({ 'display': function() { if (_Chart.c('visible')) { _Chart.setScrollDimensions(); return 'block'; } else { return 'none'; } } }) .transition() .style({ 'opacity': function() { if (_Chart.c('visible')) { return 1; } else { return 0; } } }); }; _Chart.reCalcIconPadding = function(iconDiv, padding) { var bbox = iconDiv.node().getBoundingClientRect(); d3.select(iconDiv.node().parentNode).select('.dropdownItemContainer') .style({ 'margin-left': (bbox.width + padding) + 'px' }); } _Chart.setSelectedValueByLabel = function (label) { var item = _Chart._dropdownGroup .selectAll('li.dropdownItem').filter(function (d) { return _Chart.a('Label')(d) === label; }); if (item && item.node()) { item.node().click(); } }; _Chart.setSelectedValueByIndex = function (index) { var item = _Chart._dropdownGroup .selectAll('li.dropdownItem').filter(function (d, i) { return i === index; }); if (item && item.node()) { item.node().click(); } }; _Chart.setScrollDimensions = function () { if (_Chart.c('domoScroll')) { _Chart.scroll .viewWidth(parseInt(_Chart.c('width'))) .viewHeight(parseInt(_Chart.c('height'))) .syncY(_Chart._dropdownGroup); } }; }, //************************************************** //Legacy getters/setters for backwards compatibility //************************************************** width: function(_) { if (arguments.length === 0) { return this.c('width'); } this.c('width', _); return this; }, height: function(_) { if (arguments.length === 0) { return this.c('height'); } this.c('height', _); return this; }, size: function(_) { if (arguments.length === 0) { return this.c('size'); } this.c('size', _); return this }, chartName: function(_) { if (arguments.length === 0) { return this.c('chartName') } this.c('chartName', _); return this; }, selectedIndex: function(_) { if (arguments.length === 0) { return this.c('selectedIndex'); } this.c('selectedIndex', _); return this; }, selectedValue: function(_) { if (arguments.length === 0){ return this.c('selectedValue'); } this.c('selectedValue', _); return this; }, showDropdown: function(_) { if (arguments.length === 0){ return this.c('visible'); } this.c('visible', _); return this; }, }); /***/ }, /* 1 */ /***/ function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE_1__; /***/ }, /* 2 */ /***/ function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE_2__; /***/ }, /* 3 */ /***/ function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE_3__; /***/ }, /* 4 */ /***/ function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE_4__; /***/ }, /* 5 */ /***/ function(module, exports, __webpack_require__) { // style-loader: Adds some css to the DOM by adding a <style> tag // load the styles var content = __webpack_require__(6); if(typeof content === 'string') content = [[module.id, content, '']]; // add the styles to the DOM var update = __webpack_require__(8)(content, {}); if(content.locals) module.exports = content.locals; // Hot Module Replacement if(false) { // When the styles change, update the <style> tags if(!content.locals) { module.hot.accept("!!./../../node_modules/css-loader/index.js!./dropdown.css", function() { var newContent = require("!!./../../node_modules/css-loader/index.js!./dropdown.css"); if(typeof newContent === 'string') newContent = [[module.id, newContent, '']]; update(newContent); }); } // When the module is disposed, remove the <style> tags module.hot.dispose(function() { update(); }); } /***/ }, /* 6 */ /***/ function(module, exports, __webpack_require__) { exports = module.exports = __webpack_require__(7)(); // imports // module exports.push([module.id, ".da-dropdown {\n border: 1px solid rgba(0, 0, 0, 0.2);\n -o-border-radius: 3px;\n border-radius: 3px;\n color: #555555;\n box-shadow: 0 0 0 3px rgba(84, 88, 90, 0.2);\n background: white;\n margin: 7px 0px;\n display: inline-block;\n overflow-y: scroll;\n overflow-x: hidden;\n position: absolute;\n z-index: 9000; }\n .da-dropdown:active, .da-dropdown.active {\n outline: 0;\n background-image: none; }\n .da-dropdown.dd-sm {\n font-size: 10px; }\n .da-dropdown.dd-sm .dropdownList .dropdownItem {\n padding: 3px 10px 3px 10px; }\n .da-dropdown.dd-md {\n font-size: 12px; }\n .da-dropdown.dd-md .dropdownList .dropdownItem {\n padding: 5px 10px 5px 10px; }\n .da-dropdown.dd-lg {\n font-size: 14px; }\n .da-dropdown.dd-lg .dropdownList .dropdownItem {\n padding: 7px 10px 7px 10px; }\n .da-dropdown.domoScroll {\n overflow: hidden; }\n .da-dropdown .dropdownList {\n margin: 0px;\n padding: 0px;\n list-style-type: none; }\n .da-dropdown .dropdownList .dropdownItem {\n padding: 7px 10px 7px 10px;\n cursor: pointer;\n line-height: 18px;\n min-height: 18px;\n background: #FFFFFF; }\n .da-dropdown .dropdownList .dropdownItem.active, .da-dropdown .dropdownList .dropdownItem:active {\n background: #F2F2F3; }\n .da-dropdown .dropdownList .dropdownItem.disabled {\n background: #fff;\n pointer-events: none;\n text-align: center;\n font-style: italic;\n color: #A9A9A9; }\n .da-dropdown .dropdownList .dropdownItem:hover, .da-dropdown .dropdownList .dropdownItem.hover {\n background: #C6E1F4; }\n .da-dropdown .dropdownList .dropdownItem .listItemIcon {\n float: left; }\n .da-dropdown .dropdownList .dropdownItem .dropdownItemContainer {\n word-wrap: break-word; }\n", ""]); // exports /***/ }, /* 7 */ /***/ function(module, exports) { /* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ // css base code, injected by the css-loader module.exports = function() { var list = []; // return the list of modules as css string list.toString = function toString() { var result = []; for(var i = 0; i < this.length; i++) { var item = this[i]; if(item[2]) { result.push("@media " + item[2] + "{" + item[1] + "}"); } else { result.push(item[1]); } } return result.join(""); }; // import a list of modules into the list list.i = function(modules, mediaQuery) { if(typeof modules === "string") modules = [[null, modules, ""]]; var alreadyImportedModules = {}; for(var i = 0; i < this.length; i++) { var id = this[i][0]; if(typeof id === "number") alreadyImportedModules[id] = true; } for(i = 0; i < modules.length; i++) { var item = modules[i]; // skip already imported module // this implementation is not 100% perfect for weird media query combinations // when a module is imported multiple times with different media queries. // I hope this will never occur (Hey this way we have smaller bundles) if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) { if(mediaQuery && !item[2]) { item[2] = mediaQuery; } else if(mediaQuery) { item[2] = "(" + item[2] + ") and (" + mediaQuery + ")"; } list.push(item); } } }; return list; }; /***/ }, /* 8 */ /***/ function(module, exports, __webpack_require__) { /* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ var stylesInDom = {}, memoize = function(fn) { var memo; return function () { if (typeof memo === "undefined") memo = fn.apply(this, arguments); return memo; }; }, isOldIE = memoize(function() { return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase()); }), getHeadElement = memoize(function () { return document.head || document.getElementsByTagName("head")[0]; }), singletonElement = null, singletonCounter = 0, styleElementsInsertedAtTop = []; module.exports = function(list, options) { if(false) { if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment"); } options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style> // tags it will allow on a page if (typeof options.singleton === "undefined") options.singleton = isOldIE(); // By default, add <style> tags to the bottom of <head>. if (typeof options.insertAt === "undefined") options.insertAt = "bottom"; var styles = listToStyles(list); addStylesToDom(styles, options); return function update(newList) { var mayRemove = []; for(var i = 0; i < styles.length; i++) { var item = styles[i]; var domStyle = stylesInDom[item.id]; domStyle.refs--; mayRemove.push(domStyle); } if(newList) { var newStyles = listToStyles(newList); addStylesToDom(newStyles, options); } for(var i = 0; i < mayRemove.length; i++) { var domStyle = mayRemove[i]; if(domStyle.refs === 0) { for(var j = 0; j < domStyle.parts.length; j++) domStyle.parts[j](); delete stylesInDom[domStyle.id]; } } }; } function addStylesToDom(styles, options) { for(var i = 0; i < styles.length; i++) { var item = styles[i]; var domStyle = stylesInDom[item.id]; if(domStyle) { domStyle.refs++; for(var j = 0; j < domStyle.parts.length; j++) { domStyle.parts[j](item.parts[j]); } for(; j < item.parts.length; j++) { domStyle.parts.push(addStyle(item.parts[j], options)); } } else { var parts = []; for(var j = 0; j < item.parts.length; j++) { parts.push(addStyle(item.parts[j], options)); } stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts}; } } } function listToStyles(list) { var styles = []; var newStyles = {}; for(var i = 0; i < list.length; i++) { var item = list[i]; var id = item[0]; var css = item[1]; var media = item[2]; var sourceMap = item[3]; var part = {css: css, media: media, sourceMap: sourceMap}; if(!newStyles[id]) styles.push(newStyles[id] = {id: id, parts: [part]}); else newStyles[id].parts.push(part); } return styles; } function insertStyleElement(options, styleElement) { var head = getHeadElement(); var lastStyleElementInsertedAtTop = styleElementsInsertedAtTop[styleElementsInsertedAtTop.length - 1]; if (options.insertAt === "top") { if(!lastStyleElementInsertedAtTop) { head.insertBefore(styleElement, head.firstChild); } else if(lastStyleElementInsertedAtTop.nextSibling) { head.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling); } else { head.appendChild(styleElement); } styleElementsInsertedAtTop.push(styleElement); } else if (options.insertAt === "bottom") { head.appendChild(styleElement); } else { throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'."); } } function removeStyleElement(styleElement) { styleElement.parentNode.removeChild(styleElement); var idx = styleElementsInsertedAtTop.indexOf(styleElement); if(idx >= 0) { styleElementsInsertedAtTop.splice(idx, 1); } } function createStyleElement(options) { var styleElement = document.createElement("style"); styleElement.type = "text/css"; insertStyleElement(options, styleElement); return styleElement; } function createLinkElement(options) { var linkElement = document.createElement("link"); linkElement.rel = "stylesheet"; insertStyleElement(options, linkElement); return linkElement; } function addStyle(obj, options) { var styleElement, update, remove; if (options.singleton) { var styleIndex = singletonCounter++; styleElement = singletonElement || (singletonElement = createStyleElement(options)); update = applyToSingletonTag.bind(null, styleElement, styleIndex, false); remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true); } else if(obj.sourceMap && typeof URL === "function" && typeof URL.createObjectURL === "function" && typeof URL.revokeObjectURL === "function" && typeof Blob === "function" && typeof btoa === "function") { styleElement = createLinkElement(options); update = updateLink.bind(null, styleElement); remove = function() { removeStyleElement(styleElement); if(styleElement.href) URL.revokeObjectURL(styleElement.href); }; } else { styleElement = createStyleElement(options); update = applyToTag.bind(null, styleElement); remove = function() { removeStyleElement(styleElement); }; } update(obj); return function updateStyle(newObj) { if(newObj) { if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) return; update(obj = newObj); } else { remove(); } }; } var replaceText = (function () { var textStore = []; return function (index, replacement) { textStore[index] = replacement; return textStore.filter(Boolean).join('\n'); }; })(); function applyToSingletonTag(styleElement, index, remove, obj) { var css = remove ? "" : obj.css; if (styleElement.styleSheet) { styleElement.styleSheet.cssText = replaceText(index, css); } else { var cssNode = document.createTextNode(css); var childNodes = styleElement.childNodes; if (childNodes[index]) styleElement.removeChild(childNodes[index]); if (childNodes.length) { styleElement.insertBefore(cssNode, childNodes[index]); } else { styleElement.appendChild(cssNode); } } } function applyToTag(styleElement, obj) { var css = obj.css; var media = obj.media; var sourceMap = obj.sourceMap; if(media) { styleElement.setAttribute("media", media) } if(styleElement.styleSheet) { styleElement.styleSheet.cssText = css; } else { while(styleElement.firstChild) { styleElement.removeChild(styleElement.firstChild); } styleElement.appendChild(document.createTextNode(css)); } } function updateLink(linkElement, obj) { var css = obj.css; var media = obj.media; var sourceMap = obj.sourceMap; if(sourceMap) { // http://stackoverflow.com/a/26603875 css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */"; } var blob = new Blob([css], { type: "text/css" }); var oldSrc = linkElement.href; linkElement.href = URL.createObjectURL(blob); if(oldSrc) URL.revokeObjectURL(oldSrc); } /***/ } /******/ ]) }); ;