Skip to content
1 change: 1 addition & 0 deletions zeppelin-web/src/app/notebook/notebook.css
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,4 @@
min-width: 150px;
max-width: 50%;
}

52 changes: 14 additions & 38 deletions zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $rootScope, $route, $window,
$routeParams, $location, $timeout, $compile,
$http, websocketMsgSrv, baseUrlSrv, ngToast,
saveAsService, esriLoader) {
saveAsService, esriLoader, handsonHelperService,
dataTypeService) {
var ANGULAR_FUNCTION_OBJECT_NAME_PREFIX = '_Z_ANGULAR_FUNC_';
$scope.parentNote = null;
$scope.paragraph = null;
Expand Down Expand Up @@ -913,9 +914,9 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
if (i === 0) {
columnNames.push({name: col, index: j, aggr: 'sum'});
} else {
var parsedCol = $scope.parseTableCell(col);
cols.push(parsedCol);
cols2.push({key: (columnNames[i]) ? columnNames[i].name : undefined, value: parsedCol});
//var parsedCol = $scope.parseTableCell(col);
cols.push(col);
cols2.push({key: (columnNames[i]) ? columnNames[i].name : undefined, value: col});
}
}
if (i !== 0) {
Expand Down Expand Up @@ -966,6 +967,7 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
};

var setTable = function(data, refresh) {

var renderTable = function() {
var height = $scope.paragraph.config.graph.height;
var container = angular.element('#p' + $scope.paragraph.id + '_table').css('height', height).get(0);
Expand All @@ -975,40 +977,14 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
if ($scope.hot) {
$scope.hot.destroy();
}

$scope.hot = new Handsontable(container, {
colHeaders: columnNames,
data: resultRows,
rowHeaders: false,
stretchH: 'all',
sortIndicator: true,
columnSorting: true,
contextMenu: false,
manualColumnResize: true,
manualRowResize: true,
readOnly: true,
readOnlyCellClassName: '', // don't apply any special class so we can retain current styling
fillHandle: false,
fragmentSelection: true,
disableVisualSelection: true,
cells: function(row, col, prop) {
var cellProperties = {};
cellProperties.renderer = function(instance, td, row, col, prop, value, cellProperties) {
if (value instanceof moment) {
td.innerHTML = value._i;
} else if (!isNaN(value)) {
cellProperties.format = '0,0.[00000]';
td.style.textAlign = 'left';
Handsontable.renderers.NumericRenderer.apply(this, arguments);
} else if (value.length > '%html'.length && '%html ' === value.substring(0, '%html '.length)) {
td.innerHTML = value.substring('%html'.length);
} else {
Handsontable.renderers.TextRenderer.apply(this, arguments);
}
};
return cellProperties;
}
});
if (!$scope.columns) {
$scope.columns = Array.apply(null, Array(data.columnNames.length)).map(function() {
return {type: 'text'};
});
}
$scope.hot = new Handsontable(container, handsonHelperService.getHandsonTableConfig(
$scope.columns, columnNames, resultRows));
$scope.hot.validateCells(null);
};

var retryRenderer = function() {
Expand Down
48 changes: 48 additions & 0 deletions zeppelin-web/src/app/notebook/paragraph/paragraph.css
Original file line number Diff line number Diff line change
Expand Up @@ -528,3 +528,51 @@ table.table-striped {
padding-left: 4px !important;
width: 20px;
}


.changeType {
border: 1px solid #bbb;
color: #bbb;
background: #eee;
border-radius: 2px;
padding: 2px;
font-size: 9px;
float: right;
line-height: 9px;
margin: 3px 3px 0 0;
}
.changeType:hover {
border: 1px solid #777;
color: #777;
cursor: pointer;
}
.changeType.pressed {
background-color: #999;
}
.changeTypeMenu {
position: absolute;
border: 1px solid #ccc;
margin-top: 22px;
box-shadow: 0 1px 3px -1px #323232;
background: white;
padding: 0;
font-size: 13px;
display: none;
z-index: 10;
}
.changeTypeMenu li {
text-align: left;
list-style: none;
padding: 2px 20px;
cursor: pointer;
margin-bottom: 0;
}
.changeTypeMenu li.active:before {
font-size: 12px;
content: "\2714";
margin-left: -15px;
margin-right: 3px;
}
.changeTypeMenu li:hover {
background: #eee;
}
36 changes: 36 additions & 0 deletions zeppelin-web/src/components/dataTypeService/dataType.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
(function() {

angular.module('zeppelinWebApp').service('dataTypeService', dataTypeService);

dataTypeService.$inject = [];

function dataTypeService() {

this.isNumeric = function(value) {
if (!isNaN(value)) {
if (value.length !== 0) {
if (Number(value) <= Number.MAX_SAFE_INTEGER && Number(value) >= Number.MIN_SAFE_INTEGER) {
return true;
}
}
}
return false;
};

}

})();
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
(function() {

angular.module('zeppelinWebApp').factory('handsonHelperService', handsonHelperService);

handsonHelperService.$inject = ['dataTypeService'];

function handsonHelperService(dataTypeService) {

var service = {
getHandsonTableConfig: getHandsonTableConfig
};

/*
** Public Service Functions
*/

function getHandsonTableConfig(columns, columnNames, resultRows) {
return {
colHeaders: columnNames,
data: resultRows,
rowHeaders: false,
stretchH: 'all',
sortIndicator: true,
columns: columns,
columnSorting: true,
contextMenu: false,
manualColumnResize: true,
manualRowResize: true,
readOnly: true,
readOnlyCellClassName: '',
fillHandle: false,
fragmentSelection: true,
disableVisualSelection: true,
cells: function(ro, co, pro) {
var cellProperties = {};
var colType = columns[co].type;
cellProperties.renderer = function(instance, td, row, col, prop, value, cellProperties) {
_cellRenderer(instance, td, row, col, prop, value, cellProperties, colType);
};
return cellProperties;
},
afterGetColHeader: function(col, TH) {
var instance = this;
var menu = _buildDropDownMenu(columns[col].type);
var button = _buildTypeSwitchButton();

_addButtonMenuEvent(button, menu);

Handsontable.Dom.addEvent(menu, 'click', function(event) {
if (event.target.nodeName === 'LI') {
_setColumnType(columns, event.target.data.colType, instance, col);
}
});
if (TH.firstChild.lastChild.nodeName === 'BUTTON') {
TH.firstChild.removeChild(TH.firstChild.lastChild);
}
TH.firstChild.appendChild(button);
TH.style['white-space'] = 'normal';
}
};
}

/*
** Private Service Functions
*/

function _addButtonMenuEvent(button, menu) {
Handsontable.Dom.addEvent(button, 'click', function(event) {
var changeTypeMenu;
var position;
var removeMenu;

document.body.appendChild(menu);

event.preventDefault();
event.stopImmediatePropagation();

changeTypeMenu = document.querySelectorAll('.changeTypeMenu');

for (var i = 0, len = changeTypeMenu.length; i < len; i++) {
changeTypeMenu[i].style.display = 'none';
}
menu.style.display = 'block';
position = button.getBoundingClientRect();

menu.style.top = (position.top + (window.scrollY || window.pageYOffset)) + 2 + 'px';
menu.style.left = (position.left) + 'px';

removeMenu = function(event) {
if (menu.parentNode) {
menu.parentNode.removeChild(menu);
}
};
Handsontable.Dom.removeEvent(document, 'click', removeMenu);
Handsontable.Dom.addEvent(document, 'click', removeMenu);
});
}

function _buildDropDownMenu(activeCellType) {
var menu = document.createElement('UL');
var types = ['text', 'numeric', 'date'];
var item;

menu.className = 'changeTypeMenu';

for (var i = 0, len = types.length; i < len; i++) {
item = document.createElement('LI');
if ('innerText' in item) {
item.innerText = types[i];
} else {
item.textContent = types[i];
}

item.data = {'colType': types[i]};

if (activeCellType === types[i]) {
item.className = 'active';
}
menu.appendChild(item);
}

return menu;
}

function _buildTypeSwitchButton() {
var button = document.createElement('BUTTON');

button.innerHTML = '\u25BC';
button.className = 'changeType';

return button;
}

function _cellRenderer(instance, td, row, col, prop, value, cellProperties, colType) {
if (colType === 'numeric' && dataTypeService.isNumeric(value)) {
cellProperties.format = '0,0.[00000]';
td.style.textAlign = 'left';
Handsontable.renderers.NumericRenderer.apply(this, arguments);
} else if (value.length > '%html'.length && '%html ' === value.substring(0, '%html '.length)) {
td.innerHTML = value.substring('%html'.length);
} else {
Handsontable.renderers.TextRenderer.apply(this, arguments);
}
}

function _dateValidator(value, callback) {
var d = moment(value);
return callback(d.isValid() ? true : false);
}

function _numericValidator(value, callback) {
return callback(dataTypeService.isNumeric(value));
}

function _setColumnType(columns, type, instance, col) {
columns[col].type = type;
_setColumnValidator(columns, col);
instance.updateSettings({columns: columns});
instance.validateCells(null);
if (_isColumnSorted(instance, col)) {
instance.sort(col, instance.sortOrder);
}
}

function _isColumnSorted(instance, col) {
return instance.sortingEnabled && instance.sortColumn === col;
}

function _setColumnValidator(columns, col) {
if (columns[col].type === 'numeric') {
columns[col].validator = _numericValidator;
} else if (columns[col].type === 'date') {
columns[col].validator = _dateValidator;
} else {
columns[col].validator = null;
}
}

return service;
}

})();
2 changes: 2 additions & 0 deletions zeppelin-web/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@
<script src="components/searchService/search.service.js"></script>
<script src="components/login/login.controller.js"></script>
<script src="components/elasticInputCtrl/elasticInput.controller.js"></script>
<script src="components/handsonHelperService/handsonHelper.service.js"></script>
<script src="components/dataTypeService/dataType.service.js"></script>
<!-- endbuild -->
</body>
</html>