define([
'require'
, 'jquery'
, 'nbextensions/visualpython/src/common/constant'
, 'nbextensions/visualpython/src/common/StringBuilder'
, 'nbextensions/visualpython/src/common/vpCommon'
, 'nbextensions/visualpython/src/common/component/vpSuggestInputText'
, 'nbextensions/visualpython/src/pandas/common/pandasGenerator'
, 'nbextensions/visualpython/src/common/component/vpVarSelector'
, 'nbextensions/visualpython/src/common/kernelApi'
, 'codemirror/lib/codemirror'
, 'codemirror/mode/python/python'
, 'notebook/js/codemirror-ipython'
, 'codemirror/addon/display/placeholder'
, 'codemirror/addon/display/autorefresh'
], function (requirejs, $
, vpConst, sb, vpCommon, vpSuggestInputText, pdGen, vpVarSelector, kernelApi
, codemirror) {
// Temporary constant data
const VP_DS_BTN = 'vp-ds-button';
const VP_DS = 'vp-ds';
const VP_DS_CONTAINER = 'vp-ds-container';
const VP_DS_CLOSE = 'vp-ds-close';
const VP_DS_TITLE = 'vp-ds-title';
const VP_DS_BODY = 'vp-ds-body';
const VP_DS_PREVIEW = 'vp-ds-preview';
const VP_DS_LABEL = 'vp-ds-label';
const VP_DS_PANDAS_OBJECT_BOX = 'vp-ds-pandas-object-box';
const VP_DS_PANDAS_OBJECT = 'vp-ds-pandas-object';
const VP_DS_USE_COPY = 'vp-ds-use-copy';
const VP_DS_SUBSET_TYPE = 'vp-ds-subset-type';
const VP_DS_TO_FRAME = 'vp-ds-to-frame';
/** tab selector */
const VP_DS_TAB_SELECTOR_BOX = 'vp-ds-tab-selector-box';
const VP_DS_TAB_SELECTOR_BTN = 'vp-ds-tab-selector-btn';
/** tab page */
const VP_DS_TAB_PAGE = 'vp-ds-tab-page';
const VP_DS_TAB_PAGE_BOX = 'vp-ds-tab-page-box';
const VP_DS_ROWCOL_SUBSET_TITLE = 'vp-ds-rowcol-subset-title';
const VP_DS_ROWTYPE = 'vp-ds-rowtype';
const VP_DS_ROWTYPE_BOX = 'vp-ds-rowtype-box';
/** indexing timestamp */
const VP_DS_INDEXING_TIMESTAMP = 'vp-ds-indexing-timestamp';
/** select */
const VP_DS_SELECT_CONTAINER = 'vp-ds-select-container';
const VP_DS_SELECT_LEFT = 'vp-ds-select-left';
const VP_DS_SELECT_BTN_BOX = 'vp-ds-select-btn-box';
const VP_DS_SELECT_RIGHT = 'vp-ds-select-right';
const VP_DS_SELECT_BOX = 'vp-ds-select-box';
const VP_DS_SELECT_ITEM = 'vp-ds-select-item';
/** select left */
const VP_DS_SELECT_SEARCH = 'vp-ds-select-search';
const VP_DS_DROPPABLE = 'vp-ds-droppable';
const VP_DS_DRAGGABLE = 'vp-ds-draggable';
/** select btns */
const VP_DS_SELECT_ADD_BTN = 'vp-ds-select-add-btn';
const VP_DS_SELECT_DEL_BTN = 'vp-ds-select-del-btn';
/** slicing box */
const VP_DS_SLICING_BOX = 'vp-ds-slicing-box';
/** row slice */
const VP_DS_ROW_SLICE_START = 'vp-ds-row-slice-start';
const VP_DS_ROW_SLICE_END = 'vp-ds-row-slice-end';
/** row condition */
const VP_DS_CONDITION_TBL = 'vp-ds-cond-tbl';
const VP_DS_BUTTON_ADD_CONDITION = 'vp-ds-btn-add-condition';
/** column selection/slicing */
const VP_DS_COLTYPE = 'vp-ds-coltype';
const VP_DS_COLTYPE_BOX = 'vp-ds-coltype-box';
/** column slice */
const VP_DS_COL_SLICE_START = 'vp-ds-col-slice-start';
const VP_DS_COL_SLICE_END = 'vp-ds-col-slice-end';
/** data view */
const VP_DS_DATA_VIEW_ALL_DIV = 'vp-ds-data-view-all-div';
const VP_DS_DATA_VIEW_ALL = 'vp-ds-data-view-all';
const VP_DS_DATA_VIEW_BOX = 'vp-ds-data-view-box';
const VP_DS_DATA_ERROR_BOX = 'vp-ds-data-error-box';
const VP_DS_DATA_ERROR_BOX_TITLE = 'vp-ds-data-error-box-title';
/** buttons */
const VP_DS_BUTTON_BOX = 'vp-ds-btn-box';
const VP_DS_BUTTON_APPLY = 'vp-ds-btn-apply';
const VP_DS_BUTTON_CANCEL = 'vp-ds-btn-cancel';
/** preview code */
const VP_DS_BUTTON_PREVIEW = 'vp-ds-btn-preview';
const STYLE_REQUIRED_LABEL = 'vp-orange-text';
/**
* @class SubsetEditor
* @param {object} pageThis
* @param {string} targetId
* @constructor
*/
var SubsetEditor = function(pageThis, targetId, useInputVariable=false) {
this.pageThis = pageThis;
this.targetId = targetId;
this.uuid = vpCommon.getUUID();
this.useInputVariable = useInputVariable;
// specify pandas object types
this.pdObjTypes = ['DataFrame', 'Series'];
this.state = {
viewAll: false,
// all variables list on opening popup
dataList: [],
pandasObject: '',
dataType: '',
isTimestamp: false, // is df.index timestampindex? true / false
useCopy: false,
toFrame: false,
subsetType: 'subset', // subset / loc / iloc
tabPage: 'subset', // subset / data
rowType: 'condition', // indexing / slicing / condition
rowList: [],
rowPointer: { start: -1, end: -1 },
colType: 'indexing', // indexing / slicing
columnList: [],
colPointer: { start: -1, end: -1 }
}
this.bindEvent();
this.init();
// set codemirror
this.codepreview = codemirror.fromTextArea($('#vp_previewCode')[0], {
mode: {
name: 'python',
version: 3,
singleLineStringErrors: false
}, // text-cell(markdown cell) set to 'htmlmixed'
height: '100%',
width: '100%',
indentUnit: 4,
matchBrackets: true,
readOnly:true,
autoRefresh: true,
// lineWrapping: false, // text-cell(markdown cell) set to true
// indentWithTabs: true,
theme: "ipython",
extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"},
scrollbarStyle: "null"
});
this.setPreview('# Code Preview');
// set readonly
if (useInputVariable) {
$(this.wrapSelector('.' + VP_DS_PANDAS_OBJECT)).attr('disabled', true);
}
this.loadVariables();
}
/**
* Initialize SubsetEditor's variables
* & set button next to input tag
*/
SubsetEditor.prototype.init = function() {
// load css
this.pageThis.loadCss(Jupyter.notebook.base_url + vpConst.BASE_PATH + vpConst.STYLE_PATH + "common/subsetEditor.css");
// Init variables
// set button next to input tag
var buttonTag = new sb.StringBuilder();
buttonTag.appendFormat('{2} '
, VP_DS_BTN, this.uuid, '...');
$(this.pageThis.wrapSelector('#' + this.targetId)).parent().append(buttonTag.toString());
// add popup div
var popupTag = new sb.StringBuilder();
popupTag.appendFormat('
', VP_DS, this.uuid);
popupTag.appendFormat('
', VP_DS_CONTAINER);
// title
popupTag.appendFormat('
{1}
'
, VP_DS_TITLE
, 'Subset Editor');
// close button
popupTag.appendFormatLine('
'
, VP_DS_CLOSE, 'fa fa-close');
// body start
popupTag.appendFormatLine('
', VP_DS_BODY);
// table1 start
popupTag.appendLine('
');
popupTag.appendLine(' ');
popupTag.appendLine('');
// preview code board
// popupTag.appendFormatLine('# PREVIEW CODE ', VP_DS_PREVIEW);
popupTag.appendFormatLine('
'
, VP_DS_PREVIEW, "vp_previewCode");
// pandasObject
popupTag.appendLine('');
popupTag.appendFormatLine('{1} '
, VP_DS_LABEL, 'Variable');
popupTag.appendLine('');
// pandasObject - suggestInputText
// var vpDfSuggest = new vpSuggestInputText.vpSuggestInputText();
// vpDfSuggest.addClass(VP_DS_PANDAS_OBJECT);
// vpDfSuggest.addClass('vp-input');
// vpDfSuggest.setPlaceholder('Select Object');
// vpDfSuggest.setSuggestList(function() { return [] });
// vpDfSuggest.setNormalFilter(false);
// vpDfSuggest.setValue($(this.pageThis.wrapSelector('#' + this.targetId)).val());
// popupTag.appendFormatLine(' {0}', vpDfSuggest.toTagString());
popupTag.appendFormatLine('
'
, VP_DS_PANDAS_OBJECT_BOX, 'vp-input', VP_DS_PANDAS_OBJECT);
// use copy
popupTag.appendFormatLine('{1} ', VP_DS_USE_COPY, 'Make a copy');
popupTag.appendLine(' ');
// subset type
popupTag.appendLine('');
popupTag.appendFormatLine('{1} '
, VP_DS_LABEL, 'Method');
popupTag.appendLine('');
popupTag.appendLine(this.renderSubsetType(this.state.dataType));
// to frame
popupTag.appendFormatLine('{1} ', VP_DS_TO_FRAME, 'To DataFrame');
popupTag.appendLine(' ');
// table1 end
popupTag.appendLine('
');
// divider
popupTag.appendLine('
');
// tab selector
popupTag.appendFormatLine('
', VP_DS_TAB_SELECTOR_BOX);
popupTag.appendFormatLine('
{2}
', VP_DS_TAB_SELECTOR_BTN, 'subset', 'Subset');
popupTag.appendFormatLine('
{2}
', VP_DS_TAB_SELECTOR_BTN, 'data', 'Data');
popupTag.appendLine('
');
// tab page 1 start
popupTag.appendFormatLine('
', VP_DS_TAB_PAGE, 'subset');
// row box start
popupTag.appendFormatLine('
', VP_DS_TAB_PAGE_BOX, 'subset-row');
// row type
popupTag.appendFormatLine('
{1} '
, VP_DS_ROWCOL_SUBSET_TITLE, 'Row Subset');
popupTag.appendLine(this.renderRowSubsetType(this.state.subsetType)); // VP_DS_ROWTYPE
popupTag.appendLine('
');
// row indexing
popupTag.appendFormatLine('
', VP_DS_ROWTYPE_BOX, 'indexing');
// row indexing list
popupTag.appendLine(this.renderRowIndexing(this.state.rowList));
popupTag.appendLine('
'); // VP_DS_ROWTYPE_BOX
// row slicing
popupTag.appendFormatLine('
', VP_DS_ROWTYPE_BOX, 'slicing');
// popupTag.appendFormatLine('{1} '
// , '', 'Slice');
// popupTag.appendFormatLine(' : ', VP_DS_ROW_SLICE_START, 'vp-input s', 'start');
// popupTag.appendFormatLine(' ', VP_DS_ROW_SLICE_END, 'vp-input s', 'end');
popupTag.appendLine(this.renderRowSlicingBox(this.state.rowList));
popupTag.appendLine('
'); // VP_DS_ROWTYPE_BOX
// condition box start
popupTag.appendFormatLine('
', VP_DS_ROWTYPE_BOX, 'condition', 'no-selection');
// row condition
// popupTag.appendFormatLine('{1} '
// , '', 'Conditional Subset');
popupTag.appendFormatLine('{0}', this.renderColumnConditionList(this.state.columnList));
// condition box end
popupTag.appendLine('
'); // VP_DS_ROWTYPE_BOX
// timestamp box start
popupTag.appendFormatLine('
', VP_DS_ROWTYPE_BOX, 'timestamp', 'no-selection');
// timestamp input tag
popupTag.appendFormatLine(' '
, VP_DS_INDEXING_TIMESTAMP, 'vp-input', 'Timestamp Index');
popupTag.appendLine('
'); // VP_DS_ROWTYPE_BOX
// row box end
popupTag.appendLine('
');
// column box start
popupTag.appendFormatLine('
', VP_DS_TAB_PAGE_BOX, 'subset-column');
// column type
popupTag.appendFormatLine('
{1} '
, VP_DS_ROWCOL_SUBSET_TITLE, 'Column Subset');
popupTag.appendLine(this.renderColumnSubsetType(this.state.subsetType)); // VP_DS_COLTYPE
popupTag.appendLine('
');
// column indexing
popupTag.appendFormatLine('
', VP_DS_COLTYPE_BOX, 'indexing');
// column indexing list
popupTag.appendLine(this.renderColumnIndexing(this.state.columnList));
popupTag.appendLine('
'); // VP_DS_COLTYPE_BOX
// column slicing
popupTag.appendFormatLine('
', VP_DS_COLTYPE_BOX, 'slicing');
popupTag.appendLine(this.renderColumnSlicingBox(this.state.columnList));
popupTag.appendLine('
'); // VP_DS_COLTYPE_BOX
// column box end
popupTag.appendLine('
');
// tab page 1 end
popupTag.appendLine('
');
// tab page 2 start
popupTag.appendFormatLine('
', VP_DS_TAB_PAGE, 'data');
// data view type
popupTag.appendFormatLine('
{2}
'
, VP_DS_DATA_VIEW_ALL_DIV, VP_DS_DATA_VIEW_ALL, "view all");
// data view
popupTag.appendLine(this.renderDataPage(''));
// tab page 2 end
popupTag.appendLine('
');
// apply button
popupTag.appendFormatLine('
', VP_DS_BUTTON_BOX);
// popupTag.appendFormatLine('{1} '
// , VP_DS_BUTTON_PREVIEW, 'Preview');
popupTag.appendFormatLine('{1} '
, VP_DS_BUTTON_CANCEL, 'Cancel');
popupTag.appendFormatLine('{1} '
, VP_DS_BUTTON_APPLY, 'Apply');
popupTag.appendLine('
');
// body end
popupTag.appendLine('
');
popupTag.append('
');
popupTag.append('
');
// $(vpCommon.formatString("#{0}", vpConst.VP_CONTAINER_ID)).append(popupTag.toString());
$('#vp-wrapper').append(popupTag.toString());
$(vpCommon.formatString(".{0}.{1}", VP_DS, this.uuid)).hide();
}
SubsetEditor.prototype.getAllowSubsetTypes = function() {
return this.pdObjTypes;
}
/**
* Wrap Selector for data selector popup with its uuid
* @param {string} query
*/
SubsetEditor.prototype.wrapSelector = function(query) {
return vpCommon.formatString('.{0}.{1} {2}', VP_DS, this.uuid, query);
}
///////////////////////// render //////////////////////////////////////////////////////
SubsetEditor.prototype.renderSubsetType = function(dataType) {
var subsetType = this.state.subsetType;
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_SUBSET_TYPE, 'vp-select');
tag.appendFormatLine('{2} ', 'subset', subsetType == 'subset'?'selected':'', 'subset');
tag.appendFormatLine('{2} ', 'loc', subsetType == 'loc'?'selected':'', 'loc');
tag.appendFormatLine('{2} ', 'iloc', subsetType == 'iloc'?'selected':'', 'iloc');
tag.appendLine(' ');
return tag.toString();
}
SubsetEditor.prototype.renderRowSubsetType = function(subsetType, timestamp=false) {
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_ROWTYPE, 'vp-select m');
if (subsetType == 'loc' || subsetType == 'iloc' || this.state.dataType == 'Series') {
tag.appendFormatLine('{1} ', 'indexing', 'Indexing');
}
tag.appendFormatLine('{1} ', 'slicing', 'Slicing');
if (subsetType == 'subset' || subsetType == 'loc') {
tag.appendFormatLine('{1} ', 'condition', 'Condition');
}
if ((subsetType == 'subset' || subsetType == 'loc') && timestamp) {
tag.appendFormatLine('{1} ', 'timestamp', 'Timestamp');
}
tag.appendLine(' ');
return tag.toString();
}
SubsetEditor.prototype.renderColumnSubsetType = function(subsetType) {
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_COLTYPE, 'vp-select m');
tag.appendFormatLine('{1} ', 'indexing', 'Indexing');
if (subsetType == 'loc' || subsetType == 'iloc') {
tag.appendFormatLine('{1} ', 'slicing', 'Slicing');
}
tag.appendLine(' ');
return tag.toString();
}
/**
* Render row selection list
* - search box
* - row list box (left)
* - buttons (add/del to right box)
* - apply box (right)
* @param {Array} rowList
*/
SubsetEditor.prototype.renderRowIndexing = function(rowList) {
var that = this;
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_SELECT_CONTAINER, 'select-row');
// row select - left
tag.appendFormatLine('
', VP_DS_SELECT_LEFT);
// tag.appendFormatLine(' '
// , VP_DS_SELECT_SEARCH, 'Search Row');
var vpSearchSuggest = new vpSuggestInputText.vpSuggestInputText();
vpSearchSuggest.addClass(VP_DS_SELECT_SEARCH);
vpSearchSuggest.setPlaceholder('Search Row');
vpSearchSuggest.setSuggestList(function() { return that.state.rowList; });
vpSearchSuggest.setSelectEvent(function(value) {
$(this.wrapSelector()).val(value);
$(this.wrapSelector()).trigger('change');
});
vpSearchSuggest.setNormalFilter(true);
tag.appendLine(vpSearchSuggest.toTagString());
tag.appendLine(this.renderRowSelectionBox(rowList));
tag.appendLine('
'); // VP_DS_SELECT_LEFT
// row select - buttons
tag.appendFormatLine('
', VP_DS_SELECT_BTN_BOX);
tag.appendFormatLine('{2} ', VP_DS_SELECT_ADD_BTN, 'select-row', ' ');
tag.appendFormatLine('{2} ', VP_DS_SELECT_DEL_BTN, 'select-row', ' ');
tag.appendLine('
'); // VP_DS_SELECT_BTNS
// row select - right
tag.appendFormatLine('
', VP_DS_SELECT_RIGHT);
tag.appendFormatLine('
', VP_DS_SELECT_BOX, 'right', VP_DS_DROPPABLE, 'no-selection');
tag.appendLine('
'); // VP_DS_SELECT_BOX
tag.appendLine('
'); // VP_DS_SELECT_RIGHT
tag.appendLine('
'); // VP_DS_SELECT_CONTAINER
return tag.toString();
}
/**
* Render row list box
* @param {Array} rowList
*/
SubsetEditor.prototype.renderRowSelectionBox = function(rowList) {
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_SELECT_BOX, 'left', VP_DS_DROPPABLE, 'no-selection');
// get row data and make draggable items
rowList.forEach((row, idx) => {
tag.appendFormatLine('
{7}
'
, VP_DS_SELECT_ITEM, 'select-row', VP_DS_DRAGGABLE, row.location, row.value, row.code, row.label, row.label);
});
tag.appendLine('
'); // VP_DS_SELECT_BOX
return tag.toString();
}
/**
* Render row slicing box
* - slicing start/end with suggestInput
* @param {Array} rowList
*/
SubsetEditor.prototype.renderRowSlicingBox = function(rowList) {
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_SLICING_BOX);
var vpRowStart = new vpSuggestInputText.vpSuggestInputText();
vpRowStart.addClass(VP_DS_ROW_SLICE_START);
vpRowStart.addClass('vp-input m');
vpRowStart.setPlaceholder('start');
vpRowStart.setSuggestList(function() { return rowList });
vpRowStart.setSelectEvent(function(value, item) {
$(this.wrapSelector()).val(value);
$(this.wrapSelector()).attr('data-code', item.code);
$(this.wrapSelector()).trigger('change');
});
vpRowStart.setNormalFilter(false);
var vpRowEnd = new vpSuggestInputText.vpSuggestInputText();
vpRowEnd.addClass(VP_DS_ROW_SLICE_END);
vpRowEnd.addClass('vp-input m');
vpRowEnd.setPlaceholder('end');
vpRowEnd.setSuggestList(function() { return rowList });
vpRowEnd.setSelectEvent(function(value, item) {
$(this.wrapSelector()).val(value);
$(this.wrapSelector()).attr('data-code', item.code);
$(this.wrapSelector()).trigger('change');
});
vpRowEnd.setNormalFilter(false);
tag.appendLine(vpRowStart.toTagString());
tag.appendLine(vpRowEnd.toTagString());
tag.appendLine('
');
return tag.toString();
}
/**
* Render column selection list
* - search box
* - column list box (left)
* - buttons (add/del to right box)
* - apply box (right)
* @param {Array} colList
*/
SubsetEditor.prototype.renderColumnIndexing = function(colList) {
var that = this;
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_SELECT_CONTAINER, 'select-col');
// col select - left
tag.appendFormatLine('
', VP_DS_SELECT_LEFT);
// tag.appendFormatLine(' '
// , VP_DS_SELECT_SEARCH, 'Search Column');
var vpSearchSuggest = new vpSuggestInputText.vpSuggestInputText();
vpSearchSuggest.addClass(VP_DS_SELECT_SEARCH);
vpSearchSuggest.setPlaceholder('Search Column');
vpSearchSuggest.setSuggestList(function() { return that.state.columnList; });
vpSearchSuggest.setSelectEvent(function(value) {
$(this.wrapSelector()).val(value);
$(this.wrapSelector()).trigger('change');
});
vpSearchSuggest.setNormalFilter(true);
tag.appendLine(vpSearchSuggest.toTagString());
tag.appendFormatLine(' ')
tag.appendLine(this.renderColumnSelectionBox(colList));
tag.appendLine('
'); // VP_DS_SELECT_LEFT
// col select - buttons
tag.appendFormatLine('
', VP_DS_SELECT_BTN_BOX);
tag.appendFormatLine('{2} ', VP_DS_SELECT_ADD_BTN, 'select-col', ' ');
tag.appendFormatLine('{2} ', VP_DS_SELECT_DEL_BTN, 'select-col', ' ');
tag.appendLine('
'); // VP_DS_SELECT_BTNS
// col select - right
tag.appendFormatLine('
', VP_DS_SELECT_RIGHT);
tag.appendFormatLine('
', VP_DS_SELECT_BOX, 'right', VP_DS_DROPPABLE, 'no-selection');
tag.appendLine('
'); // VP_DS_SELECT_BOX
tag.appendLine('
'); // VP_DS_SELECT_RIGHT
tag.appendLine('
'); // VP_DS_SELECT_CONTAINER
return tag.toString();
}
/**
* Render column list box
* @param {Array} colList
*/
SubsetEditor.prototype.renderColumnSelectionBox = function(colList) {
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_SELECT_BOX, 'left', VP_DS_DROPPABLE, 'no-selection');
// get col data and make draggable items
colList.forEach((col, idx) => {
tag.appendFormatLine('
{8}
'
, VP_DS_SELECT_ITEM, 'select-col', VP_DS_DRAGGABLE, col.location, col.value, col.dtype, col.code, col.label + ': \n' + col.array, col.label);
});
tag.appendLine('
'); // VP_DS_SELECT_BOX
return tag.toString();
}
/**
* Render column slicing box
* - slicing start/end with suggestInput
* @param {Array} colList
*/
SubsetEditor.prototype.renderColumnSlicingBox = function(colList) {
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_SLICING_BOX);
tag.appendFormatLine('{1} '
, '', 'Slice');
// tag.appendFormatLine(' : ', VP_DS_COL_SLICE_START, 'vp-input m', 'start');
// tag.appendFormatLine(' ', VP_DS_COL_SLICE_END, 'vp-input m', 'end');
var vpColStart = new vpSuggestInputText.vpSuggestInputText();
vpColStart.addClass(VP_DS_COL_SLICE_START);
vpColStart.addClass('vp-input m');
vpColStart.setPlaceholder('start');
vpColStart.setSuggestList(function() { return colList });
vpColStart.setSelectEvent(function(value, item) {
$(this.wrapSelector()).val(value);
$(this.wrapSelector()).attr('data-code', item.code);
$(this.wrapSelector()).trigger('change');
});
vpColStart.setNormalFilter(false);
var vpColEnd = new vpSuggestInputText.vpSuggestInputText();
vpColEnd.addClass(VP_DS_COL_SLICE_END);
vpColEnd.addClass('vp-input m');
vpColEnd.setPlaceholder('end');
vpColEnd.setSuggestList(function() { return colList });
vpColEnd.setSelectEvent(function(value, item) {
$(this.wrapSelector()).val(value);
$(this.wrapSelector()).attr('data-code', item.code);
$(this.wrapSelector()).trigger('change');
});
vpColEnd.setNormalFilter(false);
tag.appendLine(vpColStart.toTagString());
tag.appendLine(vpColEnd.toTagString());
tag.appendLine('
');
return tag.toString();
}
/**
* Render Row Condition List with columns
* - column name
* - operator
* - condition string
* - and/or connector between prev/next conditions
* @param {Array} colList
*/
SubsetEditor.prototype.renderColumnConditionList = function(colList) {
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_CONDITION_TBL);
tag.appendLine('');
tag.appendLine('');
// del col
tag.appendLine('
');
var varList = this.state.dataList;
tag.appendLine(this.renderConditionVariableInput(varList, this.state.pandasObject, this.state.dataType));
tag.appendLine('');
// tag.appendLine(' ');
tag.appendLine(this.renderConditionColumnInput(colList));
// tag.appendLine(' ');
// var vpOperSuggest = new vpSuggestInputText.vpSuggestInputText();
// vpOperSuggest.addClass('vp-input s vp-oper-list');
// vpOperSuggest.setPlaceholder("Oper");
// vpOperSuggest.setSuggestList(function() { return ['==', '!=', 'in', 'not in', '<', '<=', '>', '>=']; });
// vpOperSuggest.setSelectEvent(function(value) {
// $(this.wrapSelector()).val(value);
// $(this.wrapSelector()).trigger('change');
// });
// vpOperSuggest.setNormalFilter(false);
// tag.appendLine(vpOperSuggest.toTagString());
tag.appendFormatLine('', 'vp-select s', 'vp-oper-list');
var operList = ['', '==', '!=', 'in', 'not in', '<', '<=', '>', '>=']
operList.forEach(oper => {
tag.appendFormatLine('{1} ', oper, oper);
});
tag.appendLine(' ');
tag.appendLine(' ');
tag.appendLine('
');
tag.appendLine('');
tag.appendLine('');
tag.appendLine('and ');
tag.appendLine('or ');
tag.appendLine(' ');
// use text
tag.appendFormatLine('{3} '
, 'vp-condition-use-text', 'vp-cond-use-text', 'Uncheck it if you want to use variable or numeric values.', 'Text');
tag.appendLine('
');
tag.appendLine(' ');
tag.appendLine(' ');
tag.appendLine('');
// tag.appendLine('
');
tag.appendFormatLine('{2} '
, VP_DS_BUTTON_ADD_CONDITION, 'vp-add-col', '+ Condition');
tag.appendLine(' ');
tag.appendLine('
');
return tag.toString();
}
SubsetEditor.prototype.renderConditionVariableInput = function(varList, defaultValue, defaultValuesType) {
// var vpVarSuggest = new vpSuggestInputText.vpSuggestInputText();
// vpVarSuggest.addClass('vp-input m vp-cond-var');
// vpVarSuggest.addAttribute('data-type', defaultValuesType);
// vpVarSuggest.setPlaceholder('Variable');
// vpVarSuggest.setSuggestList(function() { return varList; });
// vpVarSuggest.setValue(defaultValue);
// vpVarSuggest.setSelectEvent(function(value, item) {
// $(this.wrapSelector()).val(value);
// $(this.wrapSelector()).attr('data-type', item.dtype);
// $(this.wrapSelector()).trigger('change');
// });
// vpVarSuggest.setNormalFilter(true);
// return vpVarSuggest.toTagString();
var dataTypes = ['DataFrame', 'Series', 'nparray', 'list', 'str'];
var varSelector = new vpVarSelector(dataTypes, defaultValuesType, true, true);
varSelector.addClass('vp-cond-var');
varSelector.setValue(defaultValue);
return varSelector.render();
}
SubsetEditor.prototype.renderConditionColumnInput = function(colList) {
// var vpColSuggest = new vpSuggestInputText.vpSuggestInputText();
// vpColSuggest.addClass('vp-input m vp-col-list');
// vpColSuggest.setPlaceholder('Column Name');
// vpColSuggest.setSuggestList(function() { return colList });
// vpColSuggest.setSelectEvent(function(value, item) {
// $(this.wrapSelector()).val(value);
// $(this.wrapSelector()).attr('data-code', item.code);
// $(this.wrapSelector()).trigger('change');
// });
// vpColSuggest.setNormalFilter(false);
// return vpColSuggest.toTagString();
var tag = new sb.StringBuilder();
tag.appendFormatLine('', 'vp-select m', 'vp-col-list');
colList.forEach(col => {
tag.appendFormatLine('{2} '
, col.code, col.value, col.label);
});
tag.appendLine(' ');
return tag.toString();
}
SubsetEditor.prototype.renderConditionCondInput = function(category) {
var vpCondSuggest = new vpSuggestInputText.vpSuggestInputText();
vpCondSuggest.addClass('vp-input m vp-condition');
if (category && category.length > 0) {
vpCondSuggest.setPlaceholder("Categorical Dtype");
vpCondSuggest.setSuggestList(function() { return category; });
vpCondSuggest.setSelectEvent(function(value) {
$(this.wrapSelector()).val(value);
$(this.wrapSelector()).trigger('change');
});
vpCondSuggest.setNormalFilter(false);
} else {
}
return vpCondSuggest.toTagString();
}
/**
* Render Data Tab Page
* @param {String} renderedText
*/
SubsetEditor.prototype.renderDataPage = function(renderedText, isHtml = true) {
var tag = new sb.StringBuilder();
tag.appendFormatLine('', VP_DS_DATA_VIEW_BOX
, 'rendered_html'); // 'rendered_html' style from jupyter output area
if (isHtml) {
tag.appendLine(renderedText);
} else {
tag.appendFormatLine('
{0} ', renderedText);
}
tag.appendLine('
');
return tag.toString();
}
///////////////////////// render end //////////////////////////////////////////////////////
///////////////////////// load ///////////////////////////////////////////////////////////
/**
* Load Data Tab Page
* - execute generated current code and get html text from jupyter kernel
* - render data page with html text (msg.content.data['text/html'])
*/
SubsetEditor.prototype.loadDataPage = function() {
var that = this;
var code = this.state.pandasObject;
// if view all is not checked, get current code
if (!this.state.viewAll) {
// get current code
code = this.generateCode();
}
// if not, get output of all data in selected pandasObject
Jupyter.notebook.kernel.execute(
code,
{
iopub: {
output: function(msg) {
if (msg.content.data) {
var htmlText = String(msg.content.data["text/html"]);
var codeText = String(msg.content.data["text/plain"]);
if (htmlText != 'undefined') {
$(that.wrapSelector('.' + VP_DS_DATA_VIEW_BOX)).replaceWith(function() {
return that.renderDataPage(htmlText);
});
} else if (codeText != 'undefined') {
// plain text as code
$(that.wrapSelector('.' + VP_DS_DATA_VIEW_BOX)).replaceWith(function() {
return that.renderDataPage(codeText, false);
});
} else {
$(that.wrapSelector('.' + VP_DS_DATA_VIEW_BOX)).replaceWith(function() {
return that.renderDataPage('');
});
}
} else {
var errorContent = new sb.StringBuilder();
if (msg.content.ename) {
errorContent.appendFormatLine('', VP_DS_DATA_ERROR_BOX);
errorContent.appendLine('
');
errorContent.appendFormatLine('
{1} '
, VP_DS_DATA_ERROR_BOX_TITLE, msg.content.ename);
if (msg.content.evalue) {
// errorContent.appendLine('
');
errorContent.appendFormatLine('
{0} ', msg.content.evalue.split('\\n').join('
'));
}
errorContent.appendLine('
');
}
$(that.wrapSelector('.' + VP_DS_DATA_VIEW_BOX)).replaceWith(function() {
return that.renderDataPage(errorContent);
});
}
}
}
},
{ silent: false, store_history: true, stop_on_error: true }
);
}
/**
* Load pandasObject
* - search available pandasObject list
* - render on VP_DS_PANDAS_OBJECT
*/
SubsetEditor.prototype.loadVariables = function() {
var that = this;
var types = that.pdObjTypes; //[]; //['DataFrame', 'Series'];
if (this.useInputVariable) {
var prevValue = $(this.pageThis.wrapSelector('#' + this.targetId)).val();
$(this.wrapSelector('.' + VP_DS_PANDAS_OBJECT)).val(prevValue);
// get type of variable
kernelApi.executePython(vpCommon.formatString('_vp_print(_vp_get_type({0}))', prevValue), function(result) {
try {
var varType = JSON.parse(result);
that.state.pandasObject = prevValue;
that.state.dataType = varType;
$(that.wrapSelector('.' + VP_DS_PANDAS_OBJECT_BOX)).replaceWith(function() {
return $(vpCommon.formatString('
'
, 'vp-input', VP_DS_PANDAS_OBJECT, prevValue));
});
that.reloadSubsetData();
} catch {
}
});
} else {
pdGen.vp_searchVarList(types, function (result) {
var varList = JSON.parse(result);
varList = varList.map(function(v) {
return { label: v.varName + ' (' + v.varType + ')', value: v.varName, dtype: v.varType };
});
that.state.dataList = varList;
// var pdObjects = varList.filter(x => that.pdObjTypes.includes(x.dtype));
// 1. Target Variable
var prevValue = $(that.wrapSelector('.' + VP_DS_PANDAS_OBJECT)).val();
// var vpDfSuggest = new vpSuggestInputText.vpSuggestInputText();
// vpDfSuggest.addClass(VP_DS_PANDAS_OBJECT);
// vpDfSuggest.addClass('vp-input');
// vpDfSuggest.setPlaceholder('Select Object');
// vpDfSuggest.setSuggestList(function() { return pdObjects; });
// vpDfSuggest.setNormalFilter(false);
// vpDfSuggest.setSelectEvent(function(selectedValue, item) {
// // trigger change
// $(that.wrapSelector('.' + VP_DS_PANDAS_OBJECT)).val(selectedValue);
// that.state.dataType = item.dtype;
// that.reloadSubsetData();
// });
// $(that.wrapSelector('.' + VP_DS_PANDAS_OBJECT)).replaceWith(function() {
// return vpDfSuggest.toTagString();
// });
$(that.wrapSelector('.' + VP_DS_PANDAS_OBJECT_BOX)).replaceWith(function() {
var pdVarSelect = new vpVarSelector(that.pdObjTypes, that.state.dataType, false, false);
pdVarSelect.addClass(VP_DS_PANDAS_OBJECT);
pdVarSelect.addBoxClass(VP_DS_PANDAS_OBJECT_BOX);
pdVarSelect.setValue(prevValue);
return pdVarSelect.render();
});
that.reloadSubsetData();
// $(that.wrapSelector('.' + VP_DS_PANDAS_OBJECT)).val(prevValue);
});
}
}
SubsetEditor.prototype.loadSubsetType = function(dataType) {
var that = this;
$(this.wrapSelector('.' + VP_DS_SUBSET_TYPE)).replaceWith(function() {
return that.renderSubsetType(dataType);
});
}
SubsetEditor.prototype.loadRowColumnSubsetType = function(subsetType, timestamp = false) {
var that = this;
// get current subset type of row & column
var rowSubset = this.state.rowType;
var colSubset = this.state.colType;
$(this.wrapSelector('.' + VP_DS_ROWTYPE)).replaceWith(function() {
return that.renderRowSubsetType(subsetType, timestamp);
});
$(this.wrapSelector('.' + VP_DS_COLTYPE)).replaceWith(function() {
return that.renderColumnSubsetType(subsetType);
});
$(this.wrapSelector('.' + VP_DS_ROWTYPE)).val(rowSubset);
$(this.wrapSelector('.' + VP_DS_COLTYPE)).val(colSubset);
var selectedRowType = $(this.wrapSelector('.' + VP_DS_ROWTYPE)).val();
var selectedColType = $(this.wrapSelector('.' + VP_DS_COLTYPE)).val();
if (selectedRowType != rowSubset) {
$(this.wrapSelector('.' + VP_DS_ROWTYPE + ' option')).eq(0).prop('selected', true);
this.state.rowType = $(this.wrapSelector('.' + VP_DS_ROWTYPE)).val();
}
if (selectedColType != colSubset) {
$(this.wrapSelector('.' + VP_DS_COLTYPE + ' option')).eq(0).prop('selected', true);
this.state.colType = $(this.wrapSelector('.' + VP_DS_COLTYPE)).val();
}
$(this.wrapSelector('.' + VP_DS_ROWTYPE)).trigger('change');
$(this.wrapSelector('.' + VP_DS_COLTYPE)).trigger('change');
}
/**
* Load Column List
* - change state.columnList
* - render column selection list
* - render column slicing box
* - render column condition list
* @param {Array} columnList
*/
SubsetEditor.prototype.loadColumnList = function(columnList) {
var that = this;
// if iloc
if (this.state.subsetType == 'iloc') {
columnList = columnList.map(function(x) {
return {
...x,
label: x.location + '',
value: x.location + '',
code: x.location + '',
};
})
}
this.state.columnList = columnList;
this.state.colPointer = { start: -1, end: -1 };
// column selection
$(this.wrapSelector('.' + VP_DS_SELECT_CONTAINER + '.select-col')).replaceWith(function() {
return that.renderColumnIndexing(columnList);
});
// column slicing
$(this.wrapSelector('.' + VP_DS_COLTYPE_BOX + ' .' + VP_DS_SLICING_BOX)).replaceWith(function() {
return that.renderColumnSlicingBox(columnList);
});
// column condition
$(this.wrapSelector('.' + VP_DS_CONDITION_TBL)).replaceWith(function() {
return that.renderColumnConditionList(columnList);
});
}
/**
* Load Row List
* - change state.rowList
* - render row selection list
* - render row slicing box
* @param {Array} rowList
*/
SubsetEditor.prototype.loadRowList = function(rowList) {
var that = this;
// if iloc
if (this.state.subsetType == 'iloc') {
rowList = rowList.map(function(x) {
return {
...x,
label: x.location + '',
value: x.location + '',
code: x.location + '',
};
})
}
this.state.rowList = rowList;
this.state.rowPointer = { start: -1, end: -1 };
// is timestampindex ?
if (rowList && rowList.length > 0 && rowList[0]['index_dtype'] == 'datetime64[ns]') {
this.state.isTimestamp = true;
} else {
this.state.isTimestamp = false;
}
// row selection
$(this.wrapSelector('.' + VP_DS_SELECT_CONTAINER + '.select-row')).replaceWith(function() {
return that.renderRowIndexing(rowList);
});
// row slicing
$(this.wrapSelector('.' + VP_DS_ROWTYPE_BOX + ' .' + VP_DS_SLICING_BOX)).replaceWith(function() {
return that.renderRowSlicingBox(rowList);
});
this.loadRowColumnSubsetType(this.state.subsetType, this.state.isTimestamp);
}
///////////////////////// load end ///////////////////////////////////////////////////////////
/**
* Bind Draggable to VP_DS_SELECT_ITEM
* - bind draggable to VP_DS_DRAGGABLE
* - bind droppable to VP_DS_DROPPABLE
* @param {string} type 'row'/'col'
*/
SubsetEditor.prototype.bindDraggable = function(type) {
var that = this;
var draggableQuery = this.wrapSelector('.' + VP_DS_DRAGGABLE + '.select-' + type);
var droppableQuery = this.wrapSelector('.select-' + type + ' .' + VP_DS_DROPPABLE);
$(draggableQuery).draggable({
// containment: '.select-' + type + ' .' + VP_DS_DROPPABLE,
// appendTo: droppableQuery,
// snap: '.' + VP_DS_DRAGGABLE,
revert: 'invalid',
cursor: 'pointer',
connectToSortable: droppableQuery + '.right',
// cursorAt: { bottom: 5, right: 5 },
helper: function() {
// selected items
var widthString = parseInt($(this).outerWidth()) + 'px';
var selectedTag = $(this).parent().find('.selected');
if (selectedTag.length <= 0) {
selectedTag = $(this);
}
return $('
').append(selectedTag.clone().addClass('moving').css({
width: widthString, border: '0.25px solid #C4C4C4'
}));
}
});
$(droppableQuery).droppable({
accept: draggableQuery,
drop: function(event, ui) {
var dropped = ui.draggable;
var droppedOn = $(this);
// is dragging on same droppable container?
if (droppedOn.get(0) == $(dropped).parent().get(0)) {
that.generateCode();
return ;
}
var dropGroup = $(dropped).parent().find('.selected:not(.moving)');
// if nothing selected(as orange_text), use dragging item
if (dropGroup.length <= 0) {
dropGroup = $(dropped);
}
$(dropGroup).detach().css({top:0, left:0}).appendTo(droppedOn);
if ($(this).hasClass('right')) {
// add
$(dropGroup).addClass('added');
} else {
// del
$(dropGroup).removeClass('added');
// sort
$(droppedOn).find('.' + VP_DS_SELECT_ITEM).sort(function(a, b) {
return ($(b).data('idx')) < ($(a).data('idx')) ? 1 : -1;
}).appendTo( $(droppedOn) );
}
// remove selection
$(droppableQuery).find('.selected').removeClass('selected');
that.state[type + 'Pointer'] = { start: -1, end: -1 };
that.generateCode();
},
over: function(event, elem) {
},
out: function(event, elem) {
}
});
}
/**
* Bind All Events
* - open popup
* - close popup
* - pandasObject select/change
* - use copy change
* - subset type change
* - tab change
* - row/column subset type change
* - row/column search value change
* - row/column indexing add/del button click
* - row/column slicing start/end value change
* - condition values change
* - condition add/del button click
* - apply button click
* - cancel button click
*/
SubsetEditor.prototype.bindEvent = function() {
var that = this;
// open popup
$(document).on('click', vpCommon.formatString('.{0}.{1}', VP_DS_BTN, this.uuid), function(event) {
that.open();
});
// close popup
$(document).on('click', this.wrapSelector('.' + VP_DS_CLOSE), function(event) {
that.close();
$(vpCommon.formatString('.{0}.{1}', VP_DS_BTN, this.uuid)).remove();
// vpCommon.removeHeadScript("vpSubsetEditor");
});
// df selection/change
$(document).on('var_changed change', this.wrapSelector('.' + VP_DS_PANDAS_OBJECT), function(event) {
var varName = $(that.wrapSelector('.' + VP_DS_PANDAS_OBJECT)).val();
that.state.dataType = event.dataType? event.dataType: that.state.dataType;
that.state.pandasObject = varName;
that.state.rowList = [];
that.state.columnList = [];
that.state.rowPointer = { start: -1, end: -1 };
that.state.colPointer = { start: -1, end: -1 };
if (varName == '') {
that.loadRowList([]);
that.loadColumnList([]);
that.generateCode();
return;
}
// that.loadSubsetType(that.state.dataType);
if (that.state.dataType == 'DataFrame') {
var colCode = vpCommon.formatString('_vp_print(_vp_get_columns_list({0}))', varName);
// get result and load column list
kernelApi.executePython(colCode, function(result) {
var colList = JSON.parse(result);
colList = colList.map(function(x) {
return {
...x,
value: x.label,
code: x.value
};
});
that.loadColumnList(colList);
that.bindDraggable('col');
that.generateCode();
});
var rowCode = vpCommon.formatString('_vp_print(_vp_get_rows_list({0}))', varName);
// get result and load column list
kernelApi.executePython(rowCode, function(result) {
var rowList = JSON.parse(result);
rowList = rowList.map(function(x) {
return {
...x,
value: x.label,
code: x.value
};
});
that.loadRowList(rowList);
that.bindDraggable('row');
that.generateCode();
});
// show column box
$(that.wrapSelector('.' + VP_DS_TAB_PAGE_BOX + '.subset-column')).show();
} else if (that.state.dataType == 'Series') {
var rowCode = vpCommon.formatString('_vp_print(_vp_get_rows_list({0}))', varName);
// get result and load column list
kernelApi.executePython(rowCode, function(result) {
var rowList = JSON.parse(result);
rowList = rowList.map(function(x) {
return {
...x,
value: x.label,
code: x.value
};
});
that.loadRowList(rowList);
that.bindDraggable('row');
that.generateCode();
});
that.loadColumnList([]);
// hide to frame
$(that.wrapSelector('.' + VP_DS_TO_FRAME)).parent().hide();
// hide column box
$(that.wrapSelector('.' + VP_DS_TAB_PAGE_BOX + '.subset-column')).hide();
}
// data page
if (that.state.tabPage == 'data') {
that.loadDataPage();
}
});
// use copy
$(document).on('change', this.wrapSelector('.' + VP_DS_USE_COPY), function(event) {
var checked = $(this).prop('checked');
that.state.useCopy = checked;
that.generateCode();
});
// subset type select
$(document).on('change', this.wrapSelector('.' + VP_DS_SUBSET_TYPE), function(event) {
var subsetType = $(this).val();
that.state.subsetType = subsetType;
that.reloadSubsetData();
// that.loadRowColumnSubsetType(subsetType, that.state.isTimestamp);
// // data page
// if (that.state.tabPage == 'data') {
// that.loadDataPage();
// } else {
// that.generateCode();
// }
});
// to frame
$(document).on('change', this.wrapSelector('.' + VP_DS_TO_FRAME), function(event) {
var checked = $(this).prop('checked');
that.state.toFrame = checked;
if (that.state.tabPage == 'data') {
that.loadDataPage();
} else {
that.generateCode();
}
});
// tab page select
$(document).on('click', this.wrapSelector('.' + VP_DS_TAB_SELECTOR_BTN), function(event) {
var page = $(this).attr('data-page');
that.state.tabPage = page;
// button toggle
$(that.wrapSelector('.' + VP_DS_TAB_SELECTOR_BTN)).removeClass('selected');
$(this).addClass('selected');
// page toggle
$(that.wrapSelector('.' + VP_DS_TAB_PAGE)).hide();
if (page == 'subset') {
// page: subset
$(that.wrapSelector('.' + VP_DS_TAB_PAGE + '.subset')).show();
} else {
// page: data
// loadDataPage
that.loadDataPage();
$(that.wrapSelector('.' + VP_DS_TAB_PAGE + '.data')).show();
}
});
// view all
$(document).on('change', this.wrapSelector('.' + VP_DS_DATA_VIEW_ALL), function(event) {
var checked = $(this).prop('checked');
that.state.viewAll = checked;
that.loadDataPage();
});
// row type selector
$(document).on('change', this.wrapSelector('.' + VP_DS_ROWTYPE), function(event) {
var rowType = $(this).val();
that.state.rowType = rowType;
// hide
$(that.wrapSelector('.' + VP_DS_ROWTYPE_BOX)).hide();
$(that.wrapSelector('.' + VP_DS_ROWTYPE_BOX + '.' + rowType)).show();
that.generateCode();
});
// column type selector
$(document).on('change', this.wrapSelector('.' + VP_DS_COLTYPE), function(event) {
var colType = $(this).val();
that.state.colType = colType;
// hide
$(that.wrapSelector('.' + VP_DS_COLTYPE_BOX)).hide();
$(that.wrapSelector('.' + VP_DS_COLTYPE_BOX + '.' + colType)).show();
that.generateCode();
});
// row indexing - timestamp
$(document).on('change', this.wrapSelector('.' + VP_DS_INDEXING_TIMESTAMP), function(event) {
that.generateCode();
});
// item indexing - search index
$(document).on('change', this.wrapSelector('.select-row .' + VP_DS_SELECT_SEARCH), function(event) {
var searchValue = $(this).val();
// filter added rows
var addedTags = $(that.wrapSelector('.select-row .' + VP_DS_SELECT_RIGHT + ' .' + VP_DS_SELECT_ITEM + '.added'));
var addedRowList = [];
for (var i = 0; i < addedTags.length; i++) {
var value = $(addedTags[i]).attr('data-rowname');
addedRowList.push(value);
}
var filteredRowList = that.state.rowList.filter(x => x.value.toString().includes(searchValue) && !addedRowList.includes(x.value.toString()));
// row indexing
$(that.wrapSelector('.select-row .' + VP_DS_SELECT_BOX + '.left')).replaceWith(function() {
return that.renderRowSelectionBox(filteredRowList);
});
// draggable
that.bindDraggable('row');
});
// item indexing - search columns
$(document).on('change', this.wrapSelector('.select-col .' + VP_DS_SELECT_SEARCH), function(event) {
var searchValue = $(this).val();
// filter added columns
var addedTags = $(that.wrapSelector('.select-col .' + VP_DS_SELECT_RIGHT + ' .' + VP_DS_SELECT_ITEM + '.added'));
var addedColumnList = [];
for (var i = 0; i < addedTags.length; i++) {
var value = $(addedTags[i]).attr('data-colname');
addedColumnList.push(value);
}
var filteredColumnList = that.state.columnList.filter(x => x.value.includes(searchValue) && !addedColumnList.includes(x.value));
// column indexing
$(that.wrapSelector('.select-col .' + VP_DS_SELECT_BOX + '.left')).replaceWith(function() {
return that.renderColumnSelectionBox(filteredColumnList);
});
// draggable
that.bindDraggable('col');
});
// item indexing
$(document).on('click', this.wrapSelector('.' + VP_DS_SELECT_ITEM), function(event) {
var dataIdx = $(this).attr('data-idx');
var idx = $(this).index();
var itemType = $(this).hasClass('select-row')? 'row':'col';
var added = $(this).hasClass('added'); // right side added item?
var selector = '.select-' + itemType;
// remove selection for select box on the other side
if (added) {
// remove selection for left side
$(that.wrapSelector('.' + VP_DS_SELECT_ITEM + '.select-' + itemType + ':not(.added)')).removeClass('selected');
// set selector
selector += '.added';
} else {
// remove selection for right(added) side
$(that.wrapSelector('.' + VP_DS_SELECT_ITEM + '.select-' + itemType + '.added')).removeClass('selected');
// set selector
selector += ':not(.added)';
}
if (that.keyboardManager.keyCheck.ctrlKey) {
// multi-select
that.state[itemType + 'Pointer'] = { start: idx, end: -1 };
$(this).toggleClass('selected');
} else if (that.keyboardManager.keyCheck.shiftKey) {
// slicing
var startIdx = that.state[itemType + 'Pointer'].start;
if (startIdx == -1) {
// no selection
that.state[itemType + 'Pointer'] = { start: idx, end: -1 };
} else if (startIdx > idx) {
// add selection from idx to startIdx
var tags = $(that.wrapSelector('.' + VP_DS_SELECT_ITEM + selector));
for (var i = idx; i <= startIdx; i++) {
$(tags[i]).addClass('selected');
}
that.state[itemType + 'Pointer'] = { start: startIdx, end: idx };
} else if (startIdx <= idx) {
// add selection from startIdx to idx
var tags = $(that.wrapSelector('.' + VP_DS_SELECT_ITEM + selector));
for (var i = startIdx; i <= idx; i++) {
$(tags[i]).addClass('selected');
}
that.state[itemType + 'Pointer'] = { start: startIdx, end: idx };
}
} else {
// single-select
that.state[itemType + 'Pointer'] = { start: idx, end: -1 };
// un-select others
$(that.wrapSelector('.' + VP_DS_SELECT_ITEM + selector)).removeClass('selected');
// select this
$(this).addClass('selected');
}
});
// item indexing - add
$(document).on('click', this.wrapSelector('.' + VP_DS_SELECT_ADD_BTN), function(event) {
var itemType = $(this).hasClass('select-row')? 'row':'col';
var selector = '.select-' + itemType + '.selected';
$(that.wrapSelector('.' + VP_DS_SELECT_ITEM + selector)).appendTo(
$(that.wrapSelector('.select-' + itemType + ' .' + VP_DS_SELECT_BOX + '.right'))
);
$(that.wrapSelector('.' + VP_DS_SELECT_ITEM + selector)).addClass('added');
$(that.wrapSelector('.' + VP_DS_SELECT_ITEM + selector)).removeClass('selected');
that.state[itemType + 'Pointer'] = { start: -1, end: -1 };
that.generateCode();
});
// item indexing - del
$(document).on('click', this.wrapSelector('.' + VP_DS_SELECT_DEL_BTN), function(event) {
var itemType = $(this).hasClass('select-row')? 'row':'col';
var selector = '.select-' + itemType + '.selected';
var targetBoxQuery = that.wrapSelector('.select-' + itemType + ' .' + VP_DS_SELECT_BOX + '.left');
var selectedTag = $(that.wrapSelector('.' + VP_DS_SELECT_ITEM + selector));
selectedTag.appendTo(
$(targetBoxQuery)
);
// sort
$(targetBoxQuery + ' .' + VP_DS_SELECT_ITEM).sort(function(a, b) {
return ($(b).data('idx')) < ($(a).data('idx')) ? 1 : -1;
}).appendTo(
$(targetBoxQuery)
);
selectedTag.removeClass('added');
selectedTag.removeClass('selected');
that.state[itemType + 'Pointer'] = { start: -1, end: -1 };
that.generateCode();
});
// row-column condition add
$(document).on('click', this.wrapSelector('.vp-add-col'), function(event) {
that.handleColumnAdd();
that.generateCode();
});
// row-column condition delete
$(document).on('click', this.wrapSelector('.vp-del-col'), function(event) {
event.stopPropagation();
var colList = $(that.wrapSelector('.' + VP_DS_CONDITION_TBL + ' tr td:not(:last)'));
if (colList.length <= 1) {
// clear
// add new column
that.handleColumnAdd();
}
// clear previous one
$(this).closest('tr').remove();
$(that.wrapSelector('.' + VP_DS_CONDITION_TBL + ' .vp-oper-connect:last')).hide();
that.generateCode();
});
// typing on slicing
$(document).on('change', this.wrapSelector('.slicing input[type="text"]'), function() {
that.generateCode();
});
// typing on condition variable
$(document).on('change var_changed', this.wrapSelector('.vp-ds-cond-tbl .vp-cond-var'), function() {
var varType = $(this).attr('data-type');
var colTag = $(this).closest('td').find('.vp-col-list');
if (varType == 'DataFrame') {
// pd Object selected
var varName = $(this).val();
if (varName == '') {
$(colTag).attr('disabled', true);
$(colTag).replaceWith(function() {
return that.renderConditionColumnInput([]);
});
that.generateCode();
return;
}
// dataframe column search
var colCode = vpCommon.formatString('_vp_print(_vp_get_columns_list({0}))', varName);
// get result and load column list
kernelApi.executePython(colCode, function(result) {
var colList = JSON.parse(result);
colList = colList.map(function(x) {
return {
...x,
value: x.label,
code: x.value
};
});
$(colTag).replaceWith(function() {
return that.renderConditionColumnInput(colList);
});
$(colTag).attr('disabled', false);
that.generateCode();
});
} else {
$(colTag).val('');
$(colTag).attr('placeholder', '');
$(colTag).attr('disabled', true);
$(colTag).replaceWith(function() {
return that.renderConditionColumnInput([]);
});
that.generateCode();
}
});
$(document).on('change', this.wrapSelector('.vp-ds-cond-tbl .vp-col-list'), function() {
var varName = $(this).closest('td').find('.vp-cond-var').val();
var colName = $(this).find('option:selected').attr('data-code');
var condTag = $(this).closest('td').find('.vp-condition');
var code = vpCommon.formatString('_vp_print(_vp_get_column_category({0}, {1}))', varName, colName);
// get result and load column list
kernelApi.executePython(code, function(result) {
var category = JSON.parse(result);
$(condTag).replaceWith(function() {
return that.renderConditionCondInput(category);
});
that.generateCode();
});
});
// use text
$(document).on('change', this.wrapSelector('.vp-ds-cond-tbl .vp-cond-use-text'), function() {
that.generateCode();
});
// typing on condition
$(document).on('change', this.wrapSelector('.vp-ds-cond-tbl input[type="text"]'), function() {
that.generateCode();
});
$(document).on('change', this.wrapSelector('.vp-ds-cond-tbl select'), function() {
that.generateCode();
});
// DEPRECATED: now it will preview code on real time(on related value changing event)
// preview code
// $(document).on('click', this.wrapSelector('.' + VP_DS_BUTTON_PREVIEW), function(event) {
// var code = that.generateCode();
// });
// apply
$(document).on('click', this.wrapSelector('.' + VP_DS_BUTTON_APPLY), function(event) {
var code = that.generateCode();
$(that.pageThis.wrapSelector('#' + that.targetId)).val(code);
$(that.pageThis.wrapSelector('#' + that.targetId)).trigger('subset_apply');
that.close();
});
// cancel
$(document).on('click', this.wrapSelector('.' + VP_DS_BUTTON_CANCEL), function(event) {
that.close();
});
///////////////////////// FIXME: make it common //////////////////////////////////////
this.keyboardManager = {
keyCode : {
ctrlKey: 17,
cmdKey: 91,
shiftKey: 16,
altKey: 18,
enter: 13,
escKey: 27
},
keyCheck : {
ctrlKey: false,
shiftKey: false
}
}
$(document).keydown(function(e) {
var keyCode = that.keyboardManager.keyCode;
if (e.keyCode == keyCode.ctrlKey || e.keyCode == keyCode.cmdKey) {
that.keyboardManager.keyCheck.ctrlKey = true;
}
if (e.keyCode == keyCode.shiftKey) {
that.keyboardManager.keyCheck.shiftKey = true;
}
}).keyup(function(e) {
var keyCode = that.keyboardManager.keyCode;
if (e.keyCode == keyCode.ctrlKey || e.keyCode == keyCode.cmdKey) {
that.keyboardManager.keyCheck.ctrlKey = false;
}
if (e.keyCode == keyCode.shiftKey) {
that.keyboardManager.keyCheck.shiftKey = false;
}
if (e.keyCode == keyCode.escKey) {
// close on esc
that.close();
}
});
}
/**
* open popup
*/
SubsetEditor.prototype.open = function() {
// reload pandasObject on open
this.loadVariables();
$(vpCommon.formatString(".{0}.{1}", VP_DS, this.uuid)).show();
}
/**
* close popup
*/
SubsetEditor.prototype.close = function() {
$(vpCommon.formatString(".{0}.{1}", VP_DS, this.uuid)).hide();
}
SubsetEditor.prototype.hideButton = function() {
$(this.pageThis.wrapSelector('.' + VP_DS_BTN + '.' + this.uuid)).hide();
}
SubsetEditor.prototype.showButton = function() {
$(this.pageThis.wrapSelector('.' + VP_DS_BTN + '.' + this.uuid)).show();
}
/**
* Handle Adding Condition
*/
SubsetEditor.prototype.handleColumnAdd = function() {
var that = this;
var clone = $(this.wrapSelector('.' + VP_DS_CONDITION_TBL + ' tr:first')).clone();
clone.find('input').val('');
clone.find('.vp-condition').attr({'placeholder': ''});
clone.find('.vp-cond-var').parent().replaceWith(function() {
return that.renderConditionVariableInput(that.state.dataList, that.state.pandasObject, that.state.dataType);
});
// clone.find('.vp-cond-var').val(this.state.pandasObject);
// set column suggest input
clone.find('.vp-col-list').replaceWith(function() {
return that.renderConditionColumnInput(that.state.columnList);
});
// set operater suggest input
// clone.find('.vp-oper-list').replaceWith(function() {
// var suggestInput = new vpSuggestInputText.vpSuggestInputText();
// suggestInput.addClass('vp-input s vp-oper-list');
// suggestInput.setPlaceholder("Oper");
// suggestInput.setSuggestList(function() { return ['==', '!=', 'and', 'or', 'in', 'not in', '<', '<=', '>', '>=']; });
// suggestInput.setSelectEvent(function(value) {
// $(this.wrapSelector()).val(value);
// $(this.wrapSelector()).trigger('change');
// });
// suggestInput.setNormalFilter(false);
// return suggestInput.toTagString();
// });
// hide last connect operator
clone.find('.vp-oper-connect').hide();
// show connect operator right before last one
$(this.wrapSelector('.' + VP_DS_CONDITION_TBL + ' .vp-oper-connect:last')).show();
clone.insertBefore(this.wrapSelector('.' + VP_DS_CONDITION_TBL + ' tr:last'));
}
/**
* Re-load subset data
* - trigger dataframe change event
*/
SubsetEditor.prototype.reloadSubsetData = function() {
$(this.wrapSelector('.' + VP_DS_PANDAS_OBJECT)).trigger('var_changed');
}
/**
* Generate Code
* - default: # PREVIEW CODE
* - get 2 types of codes
* 1) rowSelection - indexing/slicing/condition code
* 2) colSelection - indexing/slicing code
* - consider 3 types of subset frame
* 1) subset - rowSelection & colSelection using 'indexing' type
* 2) loc - subset type 'loc'
* 3) iloc - subset type 'iloc'
* - consider use copy option
*/
SubsetEditor.prototype.generateCode = function() {
var code = new sb.StringBuilder();
// dataframe
if (this.state.pandasObject == '') {
// $(this.wrapSelector('.' + VP_DS_PREVIEW)).text('# PREVIEW CODE');
this.setPreview('# Code Preview');
return '';
}
code.append(this.state.pandasObject);
// row
var rowSelection = new sb.StringBuilder();
// depend on type
if (this.state.rowType == 'indexing') {
var rowTags = $(this.wrapSelector('.' + VP_DS_SELECT_ITEM + '.select-row.added:not(.moving)'));
if (rowTags.length > 0) {
var rowList = [];
for (var i = 0; i < rowTags.length; i++) {
var rowValue = $(rowTags[i]).attr('data-code');
if (rowValue) {
rowList.push(rowValue);
}
}
rowSelection.appendFormat('[{0}]', rowList.toString());
} else {
rowSelection.append(':');
}
} else if (this.state.rowType == 'slicing') {
var start = $(this.wrapSelector('.' + VP_DS_ROW_SLICE_START)).attr('data-code');
var end = $(this.wrapSelector('.' + VP_DS_ROW_SLICE_END)).attr('data-code');
rowSelection.appendFormat('{0}:{1}', start?start:'', end?end:'');
} else if (this.state.rowType == 'condition') {
// condition
var condList = $(this.wrapSelector('.' + VP_DS_CONDITION_TBL + ' tr td:not(:last)'));
var useCondition = false;
for (var i = 0; i < condList.length; i++) {
var colTag = $(condList[i]);
var varName = colTag.find('.vp-cond-var').val();
var varType = colTag.find('.vp-cond-var').attr('data-type');
var colName = colTag.find('.vp-col-list').find('option:selected').attr('data-code');
colName = colName? colName: '';
var oper = colTag.find('.vp-oper-list').val();
var useText = colTag.find('.vp-cond-use-text').prop('checked');
var cond = colTag.find('.vp-condition').val();
var connector = i > 0? $(condList[i- 1]).find('.vp-oper-connect').val() : undefined;
// if no variable selected, pass
if (varName == "") continue;
if (useCondition) {
rowSelection.append(connector);
}
if (varType == 'DataFrame') {
rowSelection.appendFormat('({0}', varName);
colName && rowSelection.appendFormat('[{0}]', colName);
oper && rowSelection.appendFormat(' {0}', oper);
if (cond) {
// condition value as text
if (useText) {
rowSelection.appendFormat(" '{0}'", cond);
} else {
rowSelection.appendFormat(" {0}", cond);
}
}
rowSelection.append(')');
} else {
rowSelection.appendFormat('({0}', varName);
oper && rowSelection.appendFormat(' {0}', oper);
if (cond) {
// condition value as text
if (useText) {
rowSelection.appendFormat(" '{0}'", cond);
} else {
rowSelection.appendFormat(" {0}", cond);
}
}
rowSelection.append(')');
}
useCondition = true;
}
} else if (this.state.rowType == 'timestamp') {
var tsIndexing = $(this.wrapSelector('.' + VP_DS_INDEXING_TIMESTAMP)).val();
if (tsIndexing != '') {
rowSelection.appendFormat("'{0}'", tsIndexing);
} else {
rowSelection.appendFormat(":", tsIndexing);
}
} else {
rowSelection.append(':');
}
// columns
// selected colList
var colSelection = new sb.StringBuilder();
// hide to frame
$(this.wrapSelector('.' + VP_DS_TO_FRAME)).parent().hide();
if (this.state.dataType == 'DataFrame') {
if (this.state.colType == 'indexing') {
var colTags = $(this.wrapSelector('.' + VP_DS_SELECT_ITEM + '.select-col.added:not(.moving)'));
if (colTags.length > 0) {
var colList = [];
for (var i = 0; i < colTags.length; i++) {
var colValue = $(colTags[i]).attr('data-code');
if (colValue) {
colList.push(colValue);
}
}
// hide/show to frame
if (colList.length == 1) {
$(this.wrapSelector('.' + VP_DS_TO_FRAME)).parent().show();
// to frame
if (this.state.toFrame) {
colSelection.appendFormat('[{0}]', colList.toString());
} else {
colSelection.appendFormat('{0}', colList.toString());
}
} else {
colSelection.appendFormat('[{0}]', colList.toString());
}
} else {
colSelection.append(':');
}
} else if (this.state.colType == 'slicing') {
var start = $(this.wrapSelector('.' + VP_DS_COL_SLICE_START)).attr('data-code');
var end = $(this.wrapSelector('.' + VP_DS_COL_SLICE_END)).attr('data-code');
colSelection.appendFormat('{0}:{1}', start? start: '', end? end: '');
}
}
// use simple selection
if (this.state.subsetType == 'subset') {
if (rowSelection.toString() != ':' && rowSelection.toString() != '') {
code.appendFormat('[{0}]', rowSelection.toString());
}
if (colSelection.toString() != ':' && colSelection.toString() != '') {
code.appendFormat('[{0}]', colSelection.toString());
}
} else if (this.state.subsetType == 'loc') {
if (this.state.dataType == 'DataFrame') {
code.appendFormat('.loc[{0}, {1}]', rowSelection.toString(), colSelection.toString());
} else {
code.appendFormat('.loc[{0}]', rowSelection.toString());
}
} else if (this.state.subsetType == 'iloc') {
if (this.state.dataType == 'DataFrame') {
code.appendFormat('.iloc[{0}, {1}]', rowSelection.toString(), colSelection.toString());
} else {
code.appendFormat('.iloc[{0}]', rowSelection.toString());
}
}
// use copy
if (this.state.useCopy) {
code.append('.copy()');
}
// preview code
// $(this.wrapSelector('.' + VP_DS_PREVIEW)).text(code.toString());
this.setPreview(code.toString());
return code.toString();
}
SubsetEditor.prototype.setPreview = function(previewCodeStr) {
this.codepreview.setValue(previewCodeStr);
this.codepreview.save();
var that = this;
setTimeout(function() {
that.codepreview.refresh();
}, 1);
}
return SubsetEditor
});