diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..84317c2d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,63 @@ +# Contributing to the Visual Python + +Dear contributors, thanks for your interest in Visual Python.
+We welcome all skills from: +* [Programmers](#Programmers) +* [Non-programmers](#Non-programmers) +* [Designers](#Designers)
+ + +and your contribution would be greatly appreciated !

+ +## Programmers + +### Responding to an issue +1. Find an issue you would like to work on. +2. Follow the process from [GitHub Guides: Forking Projects](https://guides.github.com/activities/forking/) + +NOTE : Any submissions are understood to be under the same GPLv3 License that covers the project. + +* GUI Kit available as a Figma library: [Visual Python GUI Kit 1.0](https://www.figma.com/community/file/976035035360380841). + + +### Creating an issue +1. Go to [Issues], click [New Issue]. +2. Select the issue template: [Bug Report](https://github.com/visualpython/visualpython/issues/new?assignees=&labels=bug&template=bug_report.md&title=%5BBUG%5D+) / [Feature Request](https://github.com/visualpython/visualpython/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=) / [Blank](https://github.com/visualpython/visualpython/issues/new) +3. Write a clear and concise description. +4. Submit a new issue. + +NOTE : If you are reporting a bug, please include steps to reproduce the problem.
+ + +## Non-programmers + +### Creating & Sharing VP Notes +1. Create a data analysis task note using Visual Python. +2. Save the note as a (.vp) format. +3. Share your work and knowledge on [Visual Python Hub](https://www.visualpython.ai/vpnote). + +NOTE : Your work can be of great help for someone who struggles to find a solution. + +### Contributing to Documentation +* Help with reviewing and editing official project documentation. + +### Helping raise a better awareness of Visual Python +* Create educational material using Visual Python. +* Create content like videos, blogs that you can share your experience and ideas about Visual Python. + + +## Designers + +### Responding to a design-related issue +1. Find a design-related issue you would like to work on. +2. Follow the process from [GitHub Guides: Forking Projects](https://guides.github.com/activities/forking/) + +### Improving UI Kit +1. Take a look at the latest version on Figma: [Visual Python GUI Kit 1.0](https://www.figma.com/community/file/976035035360380841). +2. Duplicate the file to add a copy to your folder. +3. Make changes on the copy and publish the file to Figma Community as a remix version. + +NOTE : Recommend reading [Figma: Publish Community files](https://help.figma.com/hc/en-us/articles/360040035974-Publish-Community-files) before starting the work for better understanding of the system. + +
+ diff --git a/README.md b/README.md index f54789cd..ef7e57f5 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,12 @@ - - # Visual Python - [![PyPI version shields.io](https://img.shields.io/pypi/v/visualpython)](https://pypi.python.org/pypi/visualpython/) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-green)](https://www.gnu.org/licenses/gpl-3.0.html) -[![Website: VP Hub](https://img.shields.io/badge/Website-VP%20Hub-orange)](https://www.visualpython.ai) - - -
+[![Code of Conduct: Contributor Covenant](https://img.shields.io/badge/Code%20of%20Conduct-Contributor%20Covenant-blueviolet)](https://github.com/visualpython/visualpython/blob/main/CODE_OF_CONDUCT.md) ## Introduction Visual Python is a GUI-based Python code generator, developed on the Jupyter Notebook environment as an extension. -
+ + 1. Key Features * Automatically generates Python code based on a graphic user interface
@@ -39,7 +24,6 @@ Non-programmers will be able to :
* learn the Python language more easily
* manage big data with minimal coding skills
-
## Getting Started @@ -93,20 +77,18 @@ uninstall - uninstall packages upgrade - version upgrade version - version check ``` -
- -## Mission & Vision +## Mission & Vision **Mission**
To support technology and education so that anyone can leverage big data analytics to create a variety of social values. **Vision**
-To create an environment where you can learn and use big data analytics skills easily. +To create an environment where everyone can learn and use big data analytics skills easily. - -
+## Contributing +If you are interested in contributing to the Visual Python, please see [`CONTRIBUTING.md`](CONTRIBUTING.md).
+All skills from programmers, non-programmers, designers are welcomed. ## License - GNU GPLv3 (See LICENSE file). diff --git a/css/common/frameEditor.css b/css/common/frameEditor.css new file mode 100644 index 00000000..05e1d736 --- /dev/null +++ b/css/common/frameEditor.css @@ -0,0 +1,294 @@ +.vp-fe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + z-index: 1200; + + background-color: rgba(0,0,0,.4); +} + +.vp-fe-button { + width: 45px; +} + +.vp-fe-container { + position: relative; + left: 50%; + top: 50%; + transform:translate(-50%, -50%); + + min-width: 400px; + min-height: 400px; + width: 95%; + height: 95%; + + background-color: white; +} + +.vp-fe-title { + height: 30px; + padding: 5px 0px 5px 10px; + + background-color: #EEE; + border: 1px solid #ddd;; + display: flex; + flex-direction: row; + position: relative; + + font-weight: 700; +} + +.vp-fe-close, +.vp-fe-popup-close { + position: fixed; + z-index: 3; + right: 5px; + width: 20px; + height: 20px; + line-height: 20px; + top: 5px; + text-align: center; +} + +.vp-fe-body { + width: 100%; + height: calc(100% - 30px); + padding: 10px; + display: grid; + grid-row-gap: 5px; + grid-template-rows: 35px 30px 60% calc(40% - 80px); +} + +/* preview code */ +.vp-fe-preview { + width: 100%; + height: 35px; + background-image: repeating-linear-gradient( to right, var(--grid-line-color) 0, var(--grid-line-color) 0.25px, transparent 1px, transparent 5px ), repeating-linear-gradient( to bottom, var(--grid-line-color) 0, var(--grid-line-color) 0.25px, transparent 1px, transparent 5px ); + background-color: white; + border: 0.25px solid #E4E4E4; +} +.vp-fe-preview textarea { + display: none; +} + +.vp-fe-preview .CodeMirror-code .cm-variable { + background-color: rgba(47, 133, 90, 0.2); +} + +.vp-fe-preview .CodeMirror-code .cm-string { + background-color: rgba(246, 173, 85, 0.2); +} + +.vp-fe-df-box { + /* margin-bottom: 5px; */ +} + +.vp-fe #vp_feVariable { + width: 125px; + margin-left: 5px; +} + +.vp-fe-df-refresh { + cursor: pointer; +} + +.vp-fe-menu-box { + position: fixed; + top: 0; + left: 0; + background: #FFFFFF; + z-index: 70; + /* display: grid; + grid-template-columns: repeat(6, 1fr); */ +} + +.vp-fe-menu-box .vp-fe-menu-item { + height: 25px; + line-height: 25px; + background: #FFFFFF; + border: 0.25px solid #E4E4E4; + box-sizing: border-box; + box-shadow: 1px 1px 2px rgb(0 0 0 / 10%); + border-radius: 2px; + font-size: 11px; + text-align: center; + color: #696969; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + text-overflow: ellipsis; + /* overflow: hidden; */ + white-space: nowrap; + padding: 0px 5px; +} + +.vp-fe-menu-box .vp-fe-menu-item:hover { + background: #F8F8F8; +} + +.vp-fe-menu-sub-box { + display: none; + position: absolute; + left: 100%; +} + +.vp-fe-menu-item:hover .vp-fe-menu-sub-box { + display: block; +} + +.vp-fe-popup-box { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + min-width: 400px; + /* min-height: 150px; */ + width: 30%; + height: fit-content; + background-color: white; + z-index: 200; + border: 0.25px solid var(--border-gray-color); + box-shadow: 1px 1px 2px rgb(0 0 0 / 10%); +} + +.vp-fe-popup-body { + padding: 10px; +} + +.vp-fe-popup-button-box { + float: right; + padding: 5px; +} + +.vp-fe-table { + height: 100%; + background: var(--border-gray-color); + overflow: auto; +} +.vp-fe-table table { + border-collapse: separate; + margin-top: 0px; + margin-left: 0px; +} +.vp-fe-table thead th { + position: sticky; + top: 0; + background: #FFFFFF; + border-bottom: 1px solid #000000; +} + +.vp-fe-table tbody tr:nth-child(odd) { + background: #F5F5F5; +} +.vp-fe-table tbody tr:nth-child(even) { + background: #FFFFFF; +} + +.vp-fe-table th.selected { + /* color: var(--hightlight-color); */ + background: #add3fd; +} + +.vp-fe-table th:hover { + cursor: pointer; + /* background: var(--light-gray-color); */ + /* background: rgba(66, 165, 245, 0.2); */ +} + +/* row hover */ +.vp-fe-table tbody tr:hover { + background-color: rgba(66, 165, 245, 0.2); +} + +/* column hover */ +/* .vp-fe-table thead th:not(:first-child):hover::after { + background: rgba(66, 165, 245, 0.2); + content: ''; + height: 100000px; + left: 0; + position: absolute; + top: -5000px; + width: 100%; + z-index: -1; +} */ + +.vp-fe-table-more { + margin: 5px; +} + +.vp-fe-info { + width: 100%; + height: 100%; + margin: 0px; +} + +.vp-fe-info-title { + width: 100%; + height: 20px; + line-height: 20px; + font-weight: bold; + background: #F5F5F5; +} + +.vp-fe-info-content { + width: 100%; + height: calc(100% - 20px); + overflow: auto; +} + +.vp-fe-info-content pre { + /* width: 300px; */ + padding:10px; + white-space: pre-wrap; + overflow: auto; + white-space: pre-wrap; /* CSS3*/ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-all; /* Internet Explorer 5.5+ */ +} + +/** buttons */ +.vp-fe-btn-box { + position: absolute; + bottom: 10px; + right: 10px; +} +.vp-fe-btn-apply +, .vp-fe-popup-ok { + width: 80px; + height: 30px; + background: #F37704; + border: 0.25px solid #C4C4C4; + box-sizing: border-box; + border-radius: 2px; + text-align: center; + color: #FFFFFF; +} +.vp-fe-btn-apply:hover +, .vp-fe-popup-ok:hover { + background: var(--hightlight-color); +} +.vp-fe-btn-cancel +, .vp-fe-popup-cancel { + width: 80px; + height: 30px; + background: #E5E5E5; + border: 0.25px solid #C4C4C4; + box-sizing: border-box; + border-radius: 2px; + text-align: center; + color: #696969; +} +.vp-fe-btn-cancel:hover +, .vp-fe-popup-cancel:hover { + background: #ccc; +} diff --git a/css/common/subsetEditor.css b/css/common/subsetEditor.css index fdbc95b1..6d07438b 100644 --- a/css/common/subsetEditor.css +++ b/css/common/subsetEditor.css @@ -331,7 +331,7 @@ overflow: auto; } .vp-ds-data-view-box table { - width: 100%; + /* width: 100%; */ height: 100%; } .vp-ds-data-error-box { diff --git a/css/component/common.css b/css/component/common.css index cac284ce..8864552f 100644 --- a/css/component/common.css +++ b/css/component/common.css @@ -22,6 +22,10 @@ supported by Chrome, Edge, Opera and Firefox */ } +.vp-button:hover { + background: #F8F8F8; +} + .vp-button.cancel { background: #E5E5E5; } diff --git a/css/pandas/commonPandas.css b/css/pandas/commonPandas.css index 0209253a..22672e1b 100644 --- a/css/pandas/commonPandas.css +++ b/css/pandas/commonPandas.css @@ -100,6 +100,13 @@ width: 116px; } +#vp-wrapper .vp-textarea { + border: 0.25px solid var(--border-gray-color); + width: 100%; + height: 100px; + margin: 0px; +} + /* 공통 스타일 */ .w100 { width: 100%; } .w90 { width: 90%; } diff --git a/data/libraries.xml b/data/libraries.xml index 574a765e..4294629e 100644 --- a/data/libraries.xml +++ b/data/libraries.xml @@ -1221,11 +1221,16 @@ 데이터를 차트로 표현하는 함수 pandas/plot.js + + visualpython - pandas - subset + frame editor + pandas/frameEditor.js + visualpython - pandas - subset subset dataframe pandas/subset.js - + visualpython - pandas - input output diff --git a/resource/VisualPython_Example.png b/resource/VisualPython_Example.png new file mode 100644 index 00000000..82615285 Binary files /dev/null and b/resource/VisualPython_Example.png differ diff --git a/src/api_block/blockContainer.js b/src/api_block/blockContainer.js index 49fecbb1..311fdf60 100644 --- a/src/api_block/blockContainer.js +++ b/src/api_block/blockContainer.js @@ -2586,7 +2586,7 @@ define([ this.hideOptionPreviewBox(); $(VP_ID_PREFIX + VP_APIBLOCK_BOARD_OPTION_PREVIEW_BUTTON).removeClass('enabled'); - this.setNavigator(BLOCK_CODELINE_TYPE.NONE, 'Visual Python 1.1.1'); + this.setNavigator(BLOCK_CODELINE_TYPE.NONE, 'Visual Python 1.1.2'); this.setFocusedPageType(FOCUSED_PAGE_TYPE.BOARD); $('.vp-apiblock-option-tab-none').css(STR_DISPLAY, STR_BLOCK); } diff --git a/src/api_block/index.html b/src/api_block/index.html index 70894ee2..db04f1d9 100644 --- a/src/api_block/index.html +++ b/src/api_block/index.html @@ -107,7 +107,7 @@ id='vp_apiblock_option_page'>
- Visual Python 1.1.1 + Visual Python 1.1.2
diff --git a/src/common/component/vpVarSelector.js b/src/common/component/vpVarSelector.js index ba189f25..b8cbfb15 100644 --- a/src/common/component/vpVarSelector.js +++ b/src/common/component/vpVarSelector.js @@ -137,7 +137,7 @@ define([ // render variable list that.loadVariableList(varList); } catch (ex) { - console.log(ex); + // console.log(ex); } }); } diff --git a/src/common/constant.js b/src/common/constant.js index 881f8259..41ad24ea 100644 --- a/src/common/constant.js +++ b/src/common/constant.js @@ -48,7 +48,7 @@ define ([ * toolbar btn properties */ const TOOLBAR_BTN_INFO = { - HELP: "Visual Python 1.1.1" + HELP: "Visual Python 1.1.2" // , ICON: "fa-angellist" , ICON: "vp-main-icon" , ID: "vpBtnToggle" diff --git a/src/common/vpCommon.js b/src/common/vpCommon.js index 4ff4984a..26c2c9d6 100644 --- a/src/common/vpCommon.js +++ b/src/common/vpCommon.js @@ -129,6 +129,22 @@ define([ return str; } + /** + * Convert to string format if not numeric + * @param {*} code + * @returns + */ + var convertToStr = function(code) { + if (!$.isNumeric(code)) { + if (code.includes("'")) { + code = `"${code}"`; + } else { + code = `'${code}'`; + } + } + return code; + } + /** * check duplicate variable name * @param {string} varName @@ -338,5 +354,6 @@ define([ // 추가 , kernelExecute: kernelExecute , cellExecute: cellExecute + , convertToStr: convertToStr }; }); \ No newline at end of file diff --git a/src/common/vpFrameEditor.js b/src/common/vpFrameEditor.js new file mode 100644 index 00000000..130d2273 --- /dev/null +++ b/src/common/vpFrameEditor.js @@ -0,0 +1,874 @@ +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) { + + const VP_FE_BTN = 'vp-fe-btn'; + + const VP_FE = 'vp-fe'; + const VP_FE_CONTAINER = 'vp-fe-container'; + const VP_FE_TITLE = 'vp-fe-title'; + const VP_FE_CLOSE = 'vp-fe-close'; + const VP_FE_BODY = 'vp-fe-body'; + + const VP_FE_PREVIEW = 'vp-fe-preview'; + + const VP_FE_DF_BOX = 'vp-fe-df-box'; + const VP_FE_DF_REFRESH = 'vp-fe-df-refresh'; + + const VP_FE_MENU_BOX = 'vp-fe-menu-box'; + const VP_FE_MENU_ITEM = 'vp-fe-menu-item'; + const VP_FE_MENU_SUB_BOX = 'vp-fe-menu-sub-box'; + + const VP_FE_POPUP_BOX = 'vp-fe-popup-box'; + const VP_FE_POPUP_CLOSE = 'vp-fe-popup-close'; + const VP_FE_POPUP_BODY = 'vp-fe-popup-body'; + const VP_FE_POPUP_BUTTON_BOX = 'vp-fe-popup-button-box'; + const VP_FE_POPUP_CANCEL = 'vp-fe-popup-cancel'; + const VP_FE_POPUP_OK = 'vp-fe-popup-ok'; + + const VP_FE_TABLE = 'vp-fe-table'; + const VP_FE_TABLE_COLUMN = 'vp-fe-table-column'; + const VP_FE_TABLE_ROW = 'vp-fe-table-row'; + const VP_FE_ADD_COLUMN = 'vp-fe-add-column'; + const VP_FE_ADD_ROW = 'vp-fe-add-row'; + const VP_FE_TABLE_MORE = 'vp-fe-table-more'; + + const VP_FE_INFO = 'vp-fe-info'; + const VP_FE_INFO_TITLE = 'vp-fe-info-title'; + const VP_FE_INFO_CONTENT = 'vp-fe-info-content'; + + const VP_FE_BUTTON_BOX = 'vp-fe-btn-box'; + const VP_FE_BUTTON_CANCEL = 'vp-fe-btn-cancel'; + const VP_FE_BUTTON_APPLY = 'vp-fe-btn-apply'; + + // search rows count at once + const TABLE_LINES = 10; + + const FRAME_EDIT_TYPE = { + NONE: -1, + INIT: 0, + + RENAME: 2, + DROP: 3, + DROP_NA: 4, + DROP_DUP: 5, + ONE_HOT_ENCODING: 6, + SET_IDX: 7, + REPLACE: 8, + + ADD_COL: 9, + ADD_ROW: 10, + SHOW: 11 + } + + /** + * @class FrameEditor + * @param {object} pageThis + * @param {string} targetId + * @constructor + */ + var FrameEditor = function(pageThis, targetId) { + this.pageThis = pageThis; + this.targetId = targetId; + this.uuid = vpCommon.getUUID(); + + // state + this.state = { + originObj: '', + tempObj: '_vp', + selected: [], + axis: 0, + lines: TABLE_LINES, + steps: [], + popup: FRAME_EDIT_TYPE.NONE + } + + this.codepreview = undefined; + + this.bindEvent(); + this.init(); + } + + FrameEditor.prototype.wrapSelector = function(query = '') { + return vpCommon.formatString('.{0}.{1} {2}', VP_FE, this.uuid, query); + } + + FrameEditor.prototype.open = function() { + this.loadVariableList(); + + $(this.wrapSelector()).show(); + + if (!this.codepreview) { + // var previewTextarea = $('#vp_previewCode')[0]; + // var previewTextarea = $(this.wrapSelector('#vp_previewCode'))[0]; + var previewTextarea = $(this.wrapSelector('textarea'))[0]; + // if (!previewTextarea) { + // previewTextarea = $('#vp_previewCode')[0]; + // } + if (previewTextarea) { + // set codemirror + this.codepreview = codemirror.fromTextArea(previewTextarea, { + 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: true, // text-cell(markdown cell) set to true + // indentWithTabs: true, + theme: "ipython", + extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}, + scrollbarStyle: "null" + }); + this.setPreview('# Code Preview'); + this.codepreview.refresh(); + } + } else { + this.codepreview.refresh(); + } + } + + FrameEditor.prototype.close = function() { + $(this.wrapSelector()).hide(); + } + + FrameEditor.prototype.init = function() { + this.pageThis.loadCss(Jupyter.notebook.base_url + vpConst.BASE_PATH + vpConst.STYLE_PATH + "common/frameEditor.css"); + + this.renderButton(); + this.renderThis(); + + // this.setDraggableBox(); + this.setDraggableColumns(); + } + + FrameEditor.prototype.initState = function() { + this.state.selected = []; + this.state.axis = -1; + this.state.lines = TABLE_LINES; + this.state.steps = []; + } + + FrameEditor.prototype.renderButton = function() { + // set button next to input tag + var buttonTag = new sb.StringBuilder(); + buttonTag.appendFormat('' + , VP_FE_BTN, this.uuid, 'vp-button', 'Edit'); + $(this.pageThis.wrapSelector('#' + this.targetId)).parent().append(buttonTag.toString()); + } + + FrameEditor.prototype.setPreview = function(previewCodeStr) { + if (this.codepreview) { + this.codepreview.setValue(previewCodeStr); + this.codepreview.save(); + var that = this; + setTimeout(function() { + that.codepreview.refresh(); + }, 1); + } + } + + FrameEditor.prototype.renderThis = function() { + var page = new sb.StringBuilder(); + page.appendFormatLine('
', VP_FE, this.uuid); + page.appendFormatLine('
', VP_FE_CONTAINER); + + // menu box + page.appendLine(this.renderMenuBox()); + // input popup + page.appendLine(this.renderInputPopup()); + + // title + page.appendFormat('
{1}
' + , VP_FE_TITLE + , 'Frame Editor'); + + // close button + page.appendFormatLine('
' + , VP_FE_CLOSE, 'fa fa-close'); + + // body start + page.appendFormatLine('
', VP_FE_BODY); + + // preview code board + page.appendFormatLine('
' + , VP_FE_PREVIEW, "vp_fePreviewCode"); + + // Select DataFrame + page.appendFormatLine('
', VP_FE_DF_BOX); + page.appendFormatLine('', 'vp_feVariable', 'vp-orange-text', 'DataFrame'); + page.appendFormatLine(''); + page.appendFormatLine('', VP_FE_DF_REFRESH, 'fa fa-refresh'); + page.appendLine('
'); + + // Table + page.appendFormatLine('
', VP_FE_TABLE); + + page.appendLine('
'); // End of Table + + // Info Box + page.appendFormatLine('
', VP_FE_INFO); + page.appendFormatLine('
Info
', VP_FE_INFO_TITLE); + page.appendFormatLine('
content
', VP_FE_INFO_CONTENT); + page.appendLine('
'); // End of VP_FE_INFO + + page.appendLine('
'); // VP_FE_BODY + + // apply button + page.appendFormatLine('
', VP_FE_BUTTON_BOX); + page.appendFormatLine('' + , VP_FE_BUTTON_CANCEL, 'Cancel'); + page.appendFormatLine('' + , VP_FE_BUTTON_APPLY, 'Apply'); + page.appendLine('
'); + + page.appendLine('
'); // VP_FE_CONTAINER + page.appendLine('
'); // VP_FE + + $('#vp-wrapper').append(page.toString()); + $(this.wrapSelector()).hide(); + } + + FrameEditor.prototype.renderMenuBox = function() { + var page = new sb.StringBuilder(); + // Menus + page.appendFormatLine(''); // End of Menus + return page.toString(); + } + + FrameEditor.prototype.renderInputPopup = function() { + var page = new sb.StringBuilder(); + page.appendFormatLine(''); // End of Popup + return page.toString(); + } + + FrameEditor.prototype.loadVariableList = function() { + var that = this; + // load using kernel + var dataTypes = ['DataFrame']; + kernelApi.searchVarList(dataTypes, function(result) { + try { + var varList = JSON.parse(result); + // render variable list + // replace + $(that.wrapSelector('#vp_feVariable')).replaceWith(function() { + return that.renderVariableList(varList); + }); + $(that.wrapSelector('#vp_feVariable')).trigger('change'); + } catch (ex) { + // console.log(ex); + } + }); + } + + FrameEditor.prototype.renderVariableList = function(varList) { + var tag = new sb.StringBuilder(); + var beforeValue = $(this.wrapSelector('#vp_feVariable')).val(); + tag.appendFormatLine(''); // VP_VS_VARIABLES + return tag.toString(); + } + + FrameEditor.prototype.renderTable = function(renderedText, isHtml=true) { + var tag = new sb.StringBuilder(); + // Table + tag.appendFormatLine('
', VP_FE_TABLE, 'rendered_html'); + if (isHtml) { + tag.appendFormatLine('{0}
', renderedText); + // More button + tag.appendFormatLine('
More...
', VP_FE_TABLE_MORE, 'vp-button'); + } else { + tag.appendFormatLine('
{0}
', renderedText); + } + tag.appendLine('
'); // End of Table + return tag.toString(); + } + + FrameEditor.prototype.renderAddPage = function(type) { + var content = new sb.StringBuilder(); + content.appendLine(''); + content.appendFormatLine('', type); + content.appendFormatLine(''); + content.appendLine(''); + content.appendFormatLine('
', 'vp-popup-input1'); + content.appendFormatLine('', 'vp-popup-istext1','Text'); + content.appendLine('
', 'vp-popup-input2'); + content.appendFormatLine('', 'vp-popup-istext2','Text'); + content.appendLine('
'); + return content.toString(); + } + + FrameEditor.prototype.renderRenamePage = function() { + var content = new sb.StringBuilder(); + content.appendLine(''); + this.state.selected.forEach((label, idx) => { + content.appendLine(''); + content.appendFormatLine('', label); + content.appendFormatLine(''); + }); + content.appendLine('
', 'vp-popup-input' + idx); + content.appendFormatLine('', 'vp-popup-istext' + idx, 'Text'); + content.appendLine('
'); + return content.toString(); + } + + FrameEditor.prototype.openInputPopup = function(type, width=0, height=0) { + var title = ''; + var content = ''; + + switch (parseInt(type)) { + case FRAME_EDIT_TYPE.ADD_COL: + title = 'Add Column'; + content = this.renderAddPage('column'); + break; + case FRAME_EDIT_TYPE.ADD_ROW: + title = 'Add Row'; + content = this.renderAddPage('row'); + break; + case FRAME_EDIT_TYPE.RENAME: + title = 'Rename'; + content = this.renderRenamePage(); + break; + default: + type = FRAME_EDIT_TYPE.NONE; + break; + } + + this.state.popup = type; + + // set title + $(this.wrapSelector('.' + VP_FE_POPUP_BOX + ' .' + VP_FE_TITLE)).text(title); + // set content + $(this.wrapSelector('.' + VP_FE_POPUP_BODY)).html(content); + + // show popup box + $(this.wrapSelector('.' + VP_FE_POPUP_BOX)).show(); + } + + FrameEditor.prototype.getPopupContent = function() { + var type = this.state.popup; + var content = {}; + switch (parseInt(type)) { + case FRAME_EDIT_TYPE.ADD_COL: + content['name'] = $(this.wrapSelector('.vp-popup-input1')).val(); + content['nameastext'] = $(this.wrapSelector('.vp-popup-istext1')).prop('checked'); + content['value'] = $(this.wrapSelector('.vp-popup-input2')).val(); + content['valueastext'] = $(this.wrapSelector('.vp-popup-istext2')).prop('checked'); + break; + case FRAME_EDIT_TYPE.ADD_ROW: + content['name'] = $(this.wrapSelector('.vp-popup-input1')).val(); + content['nameastext'] = $(this.wrapSelector('.vp-popup-istext1')).prop('checked'); + content['value'] = $(this.wrapSelector('.vp-popup-input2')).val(); + content['valueastext'] = $(this.wrapSelector('.vp-popup-istext2')).prop('checked'); + break; + case FRAME_EDIT_TYPE.RENAME: + this.state.selected.forEach((label, idx) => { + var value = $(this.wrapSelector('.vp-popup-input'+idx)).val(); + var istext = $(this.wrapSelector('.vp-popup-istext'+idx)).prop('checked'); + content[idx] = { + label: label, + value: value, + istext: istext + }; + }); + break; + default: + break; + } + return content; + } + + FrameEditor.prototype.closeInputPopup = function() { + $(this.wrapSelector('.' + VP_FE_POPUP_BOX)).hide(); + } + + FrameEditor.prototype.setDraggableBox = function() { + $('.' + VP_FE_POPUP_BOX).draggable({ + containment: '.' + VP_FE_BODY + }); + } + + FrameEditor.prototype.setDraggableColumns = function() { + + } + + FrameEditor.prototype.loadInfo = function() { + var that = this; + + // get selected columns/indexes + var selected = []; + $(this.wrapSelector('.' + VP_FE_TABLE + ' th.selected')).each((idx, tag) => { + var name = $(tag).attr('data-label'); + selected.push(name); + }); + this.state.selected = selected; + + var code = new sb.StringBuilder(); + code.appendFormat("{0}", this.state.tempObj); + if (this.state.selected != '') { + var rowCode = ':'; + var colCode = ':'; + if (this.state.axis == 0) { + rowCode = '[' + this.state.selected.join(',') + ']'; + } + if (this.state.axis == 1) { + colCode = '[' + this.state.selected.join(',') + ']'; + } + code.appendFormat(".loc[{0},{1}]", rowCode, colCode); + } + code.append(".value_counts()"); + kernelApi.executePython(code.toString(), function(result) { + $(that.wrapSelector('.' + VP_FE_INFO_CONTENT)).replaceWith(function() { + // return vpCommon.formatString('
{1}
', VP_FE_INFO_CONTENT, result); + return vpCommon.formatString('
{1}
', VP_FE_INFO_CONTENT, result); + }); + }); + } + + FrameEditor.prototype.getCode = function(type, content={}) { + var tempObj = this.state.tempObj; + var orgObj = this.state.originObj; + + if (!orgObj || orgObj == '') { + // object not selected + + return ''; + } + + var selectedName = this.state.selected.join(','); + var axis = this.state.axis; + + var code = new sb.StringBuilder(); + switch (parseInt(type)) { + case FRAME_EDIT_TYPE.INIT: + code.appendFormat('{0} = {1}.copy()', tempObj, orgObj); + break; + case FRAME_EDIT_TYPE.DROP: + code.appendFormat("{0}.drop([{1}], axis={2}, inplace=True)", tempObj, selectedName, axis); + break; + case FRAME_EDIT_TYPE.RENAME: + var renameStr = new sb.StringBuilder(); + Object.keys(content).forEach((key, idx) => { + if (idx == 0) { + renameStr.appendFormat("{0}: {1}", content[key].label, convertToStr(content[key].value, content[key].istext)); + } else { + renameStr.appendFormat(", {0}: {1}", content[key].label, convertToStr(content[key].value, content[key].istext)); + } + }); + code.appendFormat("{0}.rename({1}={{2}}, inplace=True)", tempObj, axis==0?'index':'columns', renameStr.toString()); + break; + case FRAME_EDIT_TYPE.DROP_NA: + var locObj = ''; + if (axis == 0) { + locObj = vpCommon.formatString('.loc[[{0}],:]', selectedName); + } else { + locObj = vpCommon.formatString('.loc[:,[{0}]]', selectedName); + } + code.appendFormat("{0}{1}.dropna(axis={2}, inplace=True)", tempObj, locObj, axis); + break; + case FRAME_EDIT_TYPE.DROP_DUP: + if (axis == 0) { + locObj = vpCommon.formatString('.loc[[{0}],:]', selectedName); + } else { + locObj = vpCommon.formatString('.loc[:,[{0}]]', selectedName); + } + code.appendFormat("{0}{1}.drop_duplicates(axis={2}, inplace=True)", tempObj, locObj, axis); + break; + case FRAME_EDIT_TYPE.ONE_HOT_ENCODING: + break; + case FRAME_EDIT_TYPE.SET_IDX: + break; + case FRAME_EDIT_TYPE.REPLACE: + code.appendFormat("{0}.replace({1}, inplace=True)", tempObj, JSON.stringify(content).replaceAll('"', "'")); + break; + case FRAME_EDIT_TYPE.ADD_COL: + var name = convertToStr(content.name, content.nameastext); + var value = convertToStr(content.value, content.valueastext); + code.appendFormat("{0}[{1}] = {2}", tempObj, name, value); + break; + case FRAME_EDIT_TYPE.ADD_ROW: + var name = convertToStr(content.name, content.nameastext); + var value = convertToStr(content.value, content.valueastext); + code.appendFormat("{0}.loc[{1}] = {2}", tempObj, name, value); + break; + case FRAME_EDIT_TYPE.SHOW: + break; + } + + return code.toString(); + } + + FrameEditor.prototype.loadCode = function(codeStr) { + var that = this; + + if (code == '') { + return ; + } + + var tempObj = this.state.tempObj; + var lines = this.state.lines; + + var code = new sb.StringBuilder(); + code.appendLine(codeStr); + code.appendFormat("{0}.head({1}).to_json(orient='{2}')", tempObj, lines, 'split'); + console.log(code.toString()); + kernelApi.executePython(code.toString(), function(result) { + try { + var data = JSON.parse(result.substr(1,result.length - 2).replaceAll('\\\\', '\\')); + console.log(data); + var columnList = data.columns; + var indexList = data.index; + var dataList = data.data; + + // table + var table = new sb.StringBuilder(); + // table.appendFormatLine('', 1, 'dataframe'); + table.appendLine(''); + table.appendLine(''); + columnList && columnList.forEach(col => { + var colLabel = convertToStr(col, typeof col == 'string'); + var colClass = ''; + if (that.state.axis == 1 && that.state.selected.includes(colLabel)) { + colClass = 'selected'; + } + table.appendFormatLine('', colLabel, 1, VP_FE_TABLE_COLUMN, colClass, col); + }); + // add column + table.appendFormatLine('', VP_FE_ADD_COLUMN, 'fa fa-plus'); + + table.appendLine(''); + table.appendLine(''); + table.appendLine(''); + + dataList && dataList.forEach((row, idx) => { + table.appendLine(''); + var idxName = indexList[idx]; + var idxLabel = convertToStr(idxName, typeof idxName == 'string'); + var idxClass = ''; + if (that.state.axis == 0 && that.state.selected.includes(idxLabel)) { + idxClass = 'selected'; + } + table.appendFormatLine('', idxLabel, 0, VP_FE_TABLE_ROW, idxClass, idxName); + row.forEach(cell => { + if (cell == null) { + cell = 'NaN'; + } + table.appendFormatLine('', cell); + }); + // empty data + // table.appendLine(''); + table.appendLine(''); + }); + // add row + table.appendLine(''); + table.appendFormatLine('', VP_FE_ADD_ROW, 'fa fa-plus'); + table.appendLine(''); + table.appendLine(''); + $(that.wrapSelector('.' + VP_FE_TABLE)).replaceWith(function() { + return that.renderTable(table.toString()); + }); + // load info + that.loadInfo(); + // add to stack + that.state.steps.push(codeStr); + that.setPreview(codeStr); + } catch (err) { + console.log(err); + } + }); + } + + + FrameEditor.prototype.bindEvent = function() { + var that = this; + // open popup + $(document).on('click', vpCommon.formatString('.{0}.{1}', VP_FE_BTN, this.uuid), function(event) { + if (!$(this).hasClass('disabled')) { + that.open(); + } + }); + + // close popup + $(document).on('click', this.wrapSelector('.' + VP_FE_CLOSE), function(event) { + that.close(); + + $(vpCommon.formatString('.{0}.{1}', VP_FE_BTN, this.uuid)).remove(); + // vpCommon.removeHeadScript("vpSubsetEditor"); + }); + + // select df + $(document).on('change', this.wrapSelector('#vp_feVariable'), function() { + // set temporary df + var origin = $(this).val(); + + // initialize state values + that.state.originObj = origin; + that.state.tempObj = '_vp'; + that.initState(); + + // load code with temporary df + that.loadCode(that.getCode(FRAME_EDIT_TYPE.INIT)); + that.loadInfo(); + }); + + // refresh df + $(document).on('click', this.wrapSelector('.vp-fe-df-refresh'), function() { + that.loadVariableList(); + }); + + // menu on column + $(document).on('contextmenu', this.wrapSelector('.' + VP_FE_TABLE + ' .' + VP_FE_TABLE_COLUMN), function(event) { + event.preventDefault(); + var hasSelected = $(this).hasClass('selected'); + $(that.wrapSelector('.' + VP_FE_TABLE + ' .' + VP_FE_TABLE_ROW)).removeClass('selected'); + // select col/idx + if (!hasSelected) { + $(this).addClass('selected'); + var newAxis = $(this).attr('data-axis'); + that.state.axis = newAxis; + } + + that.loadInfo(); + + // show menu + var thisPos = $(this).position(); + var thisRect = $(this)[0].getBoundingClientRect(); + that.showMenu(thisPos.left, thisPos.top + thisRect.height); + }); + + // menu on row + $(document).on('contextmenu', this.wrapSelector('.' + VP_FE_TABLE + ' .' + VP_FE_TABLE_ROW), function(event) { + event.preventDefault(); + var hasSelected = $(this).hasClass('selected'); + $(that.wrapSelector('.' + VP_FE_TABLE + ' .' + VP_FE_TABLE_COLUMN)).removeClass('selected'); + // select col/idx + if (!hasSelected) { + $(this).addClass('selected'); + var newAxis = $(this).attr('data-axis'); + that.state.axis = newAxis; + } + + that.loadInfo(); + + // show menu + var thisPos = $(this).position(); + var thisRect = $(this)[0].getBoundingClientRect(); + var tblPos = $(that.wrapSelector('.' + VP_FE_TABLE)).position(); + that.showMenu(tblPos.left + thisRect.width, tblPos.top + thisPos.top); + }); + + // hide menu + $(document).on('click', function(evt) { + if (evt.target.id != 'vp_apiblock_menu_box') { + // close menu + that.hideMenu(); + } + }); + + // select column + $(document).on('click', this.wrapSelector('.' + VP_FE_TABLE + ' .' + VP_FE_TABLE_COLUMN), function() { + var hasSelected = $(this).hasClass('selected'); + $(that.wrapSelector('.' + VP_FE_TABLE + ' .' + VP_FE_TABLE_ROW)).removeClass('selected'); + if (!hasSelected) { + $(this).addClass('selected'); + var newAxis = $(this).attr('data-axis'); + that.state.axis = newAxis; + } else { + $(this).removeClass('selected'); + } + + that.loadInfo(); + }); + + // select row + $(document).on('click', this.wrapSelector('.' + VP_FE_TABLE + ' .' + VP_FE_TABLE_ROW), function() { + var hasSelected = $(this).hasClass('selected'); + $(that.wrapSelector('.' + VP_FE_TABLE + ' .' + VP_FE_TABLE_COLUMN)).removeClass('selected'); + if (!hasSelected) { + $(this).addClass('selected'); + var newAxis = $(this).attr('data-axis'); + that.state.axis = newAxis; + } else { + $(this).removeClass('selected'); + } + + that.loadInfo(); + }); + + // add column + $(document).on('click', this.wrapSelector('.' + VP_FE_ADD_COLUMN), function() { + // add column + that.openInputPopup(FRAME_EDIT_TYPE.ADD_COL); + }); + + // add row + $(document).on('click', this.wrapSelector('.' + VP_FE_ADD_ROW), function() { + // add row + that.openInputPopup(FRAME_EDIT_TYPE.ADD_ROW); + }); + + // more rows + $(document).on('click', this.wrapSelector('.' + VP_FE_TABLE_MORE), function() { + that.state.lines += TABLE_LINES; + that.loadCode(that.getCode(FRAME_EDIT_TYPE.SHOW)); + }); + + // click menu item + $(document).on('click', this.wrapSelector('.' + VP_FE_MENU_ITEM), function(event) { + event.stopPropagation(); + var editType = $(this).attr('data-type'); + switch (parseInt(editType)) { + case FRAME_EDIT_TYPE.ADD_COL: + case FRAME_EDIT_TYPE.ADD_ROW: + case FRAME_EDIT_TYPE.RENAME: + that.openInputPopup(editType); + return; + } + that.loadCode(that.getCode(editType)); + }); + + // ok input popup + $(document).on('click', this.wrapSelector('.' + VP_FE_POPUP_OK), function() { + // TODO: ok input popup + that.loadCode(that.getCode(that.state.popup, that.getPopupContent())); + that.closeInputPopup(); + }); + + // cancel input popup + $(document).on('click', this.wrapSelector('.' + VP_FE_POPUP_CANCEL), function() { + that.closeInputPopup(); + }); + + // close input popup + $(document).on('click', this.wrapSelector('.' + VP_FE_POPUP_CLOSE), function() { + that.closeInputPopup(); + }); + + // click cancel + $(document).on('click', this.wrapSelector('.' + VP_FE_BUTTON_CANCEL), function() { + that.close(); + }); + + // click apply + $(document).on('click', this.wrapSelector('.' + VP_FE_BUTTON_APPLY), function() { + $(that.pageThis.wrapSelector('#' + that.targetId)).val(that.state.steps.join('\n')); + $(that.pageThis.wrapSelector('#' + that.targetId)).trigger('frame_apply'); + that.close(); + }); + } + + FrameEditor.prototype.showMenu = function(left, top) { + if (this.state.axis == 0) { + // row + + } else if (this.state.axis == 1) { + // column + + } + $(this.wrapSelector(vpCommon.formatString('.{0}', VP_FE_MENU_BOX))).css({ top: top, left: left }) + $(this.wrapSelector(vpCommon.formatString('.{0}', VP_FE_MENU_BOX))).show(); + } + + FrameEditor.prototype.hideMenu = function() { + $(this.wrapSelector(vpCommon.formatString('.{0}', VP_FE_MENU_BOX))).hide(); + } + + var convertToStr = function(code, isText) { + if (isText) { + code = "'" + code + "'"; + } + return code; + } + + return FrameEditor; +}); \ No newline at end of file diff --git a/src/common/vpSubsetEditor.js b/src/common/vpSubsetEditor.js index 6244a41c..10f1badb 100644 --- a/src/common/vpSubsetEditor.js +++ b/src/common/vpSubsetEditor.js @@ -1622,39 +1622,44 @@ define([ * open popup */ SubsetEditor.prototype.open = function() { + $(this.wrapSelector()).show(); + if (!this.codepreview) { // var previewTextarea = $('#vp_previewCode')[0]; - var previewTextarea = $(this.wrapSelector('#vp_previewCode'))[0]; - // if (wrappedTextarea) { - // previewTextarea = wrappedTextarea; + // var previewTextarea = $(this.wrapSelector('#vp_previewCode'))[0]; + var previewTextarea = $(this.wrapSelector('textarea'))[0]; + // if (!previewTextarea) { + // previewTextarea = $('#vp_previewCode')[0]; // } - // set codemirror - this.codepreview = codemirror.fromTextArea(previewTextarea, { - 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'); + if (previewTextarea) { + // set codemirror + this.codepreview = codemirror.fromTextArea(previewTextarea, { + 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'); + this.codepreview.refresh(); + } + } else { + this.codepreview.refresh(); } - this.codepreview.refresh(); // reload pandasObject on open this.loadVariables(); - - $(this.wrapSelector()).show(); } /** @@ -1926,4 +1931,4 @@ define([ } return SubsetEditor -}); \ No newline at end of file +}); diff --git a/src/pandas/common/commonPandas.js b/src/pandas/common/commonPandas.js index 60cd995f..37c0eb60 100644 --- a/src/pandas/common/commonPandas.js +++ b/src/pandas/common/commonPandas.js @@ -5353,6 +5353,29 @@ define([ label: 'Return to' } ] + }, + 'pd126': { + id: 'frame_editor', + name: 'Frame Editor', + library: 'pandas', + description : 'pandas object editor', + code: '${o0} = ${i0}', + input: [ + { + name:'i0', + type:'var', + label: 'Code', + component: 'textarea', + var_type: ['DataFrame'] + } + ], + output: [ + { + name:'o0', + type:'var', + label: 'Return to' + } + ] } } diff --git a/src/pandas/common/pandasGenerator.js b/src/pandas/common/pandasGenerator.js index 85946008..0ab6a784 100644 --- a/src/pandas/common/pandasGenerator.js +++ b/src/pandas/common/pandasGenerator.js @@ -179,6 +179,15 @@ define([ vp_generateVarSelect(tag, obj.var_type, obj.value); tblInput.appendChild(tag); break; + case 'textarea': + var textarea = $(``); + // cell metadata test + if (getValue && obj.value != undefined) { + // metadata 에 저장된 값으로 표시 + textarea.val(obj.value); + } + $(tblInput).append(textarea); + break; case 'table': // break; case 'file': diff --git a/src/pandas/frameEditor.js b/src/pandas/frameEditor.js new file mode 100644 index 00000000..1295f465 --- /dev/null +++ b/src/pandas/frameEditor.js @@ -0,0 +1,136 @@ +define([ + 'require' + , 'jquery' + , 'nbextensions/visualpython/src/common/vpCommon' + , 'nbextensions/visualpython/src/common/constant' + , 'nbextensions/visualpython/src/common/StringBuilder' + , 'nbextensions/visualpython/src/common/vpFuncJS' + , 'nbextensions/visualpython/src/common/kernelApi' + , 'nbextensions/visualpython/src/pandas/common/commonPandas' + , 'nbextensions/visualpython/src/pandas/common/pandasGenerator' + , 'nbextensions/visualpython/src/common/vpFrameEditor' +], function (requirejs, $, vpCommon, vpConst, sb, vpFuncJS, kernelApi, libPandas, pdGen + , vpFrameEditor) { + // 옵션 속성 + const funcOptProp = { + stepCount : 1 + , funcName : "Frame Editor" + , funcID : "pd_frameEditor" + , libID : "pd126" + } + + /** + * html load 콜백. 고유 id 생성하여 부과하며 js 객체 클래스 생성하여 컨테이너로 전달 + * @param {function} callback 호출자(컨테이너) 의 콜백함수 + */ + var optionLoadCallback = function(callback, meta) { + // document.getElementsByTagName("head")[0].appendChild(link); + // 컨테이너에서 전달된 callback 함수가 존재하면 실행. + if (typeof(callback) === 'function') { + var uuid = vpCommon.getUUID(); + // 최대 10회 중복되지 않도록 체크 + for (var idx = 0; idx < 10; idx++) { + // 이미 사용중인 uuid 인 경우 다시 생성 + if ($(vpConst.VP_CONTAINER_ID).find("." + uuid).length > 0) { + uuid = vpCommon.getUUID(); + } + } + $(vpCommon.wrapSelector(vpCommon.formatString("#{0}", vpConst.OPTION_GREEN_ROOM))).find(vpCommon.formatString(".{0}", vpConst.API_OPTION_PAGE)).addClass(uuid); + + // 옵션 객체 생성 + var pdPackage = new PandasPackage(uuid); + pdPackage.metadata = meta; + + // 옵션 속성 할당. + pdPackage.setOptionProp(funcOptProp); + // html 설정. + pdPackage.initHtml(); + callback(pdPackage); // 공통 객체를 callback 인자로 전달 + } + } + + /** + * html 로드. + * @param {function} callback 호출자(컨테이너) 의 콜백함수 + */ + var initOption = function(callback, meta) { + vpCommon.loadHtml(vpCommon.wrapSelector(vpCommon.formatString("#{0}", vpConst.OPTION_GREEN_ROOM)), "pandas/common/commonPandas.html", optionLoadCallback, callback, meta); + } + + /** + * 본 옵션 처리 위한 클래스 + * @param {String} uuid 고유 id + */ + var PandasPackage = function(uuid) { + this.uuid = uuid; // Load html 영역의 uuid. + // pandas 함수 + this.package = libPandas._PANDAS_FUNCTION[funcOptProp.libID]; + } + + + /** + * vpFuncJS 에서 상속 + */ + PandasPackage.prototype = Object.create(vpFuncJS.VpFuncJS.prototype); + + /** + * 유효성 검사 + * @returns 유효성 검사 결과. 적합시 true + */ + PandasPackage.prototype.optionValidation = function() { + return true; + + // 부모 클래스 유효성 검사 호출. + // vpFuncJS.VpFuncJS.prototype.optionValidation.apply(this); + } + + + /** + * html 내부 binding 처리 + */ + PandasPackage.prototype.initHtml = function() { + this.loadCss(Jupyter.notebook.base_url + vpConst.BASE_PATH + vpConst.STYLE_PATH + "pandas/commonPandas.css"); + + this.bindOptions(); + + this.subsetEditor = new vpFrameEditor(this, "i0"); + } + + /** + * Pandas 기본 패키지 바인딩 + */ + PandasPackage.prototype.bindOptions = function() { + // HTML 구성 + pdGen.vp_showInterface(this); + // if it has no additional options, remove that box + if (this.package.variable == undefined || this.package.variable.length <= 0) { + $(this.wrapSelector('#vp_optionBox')).closest('div.vp-accordion-container').remove(); + } + }; + + /** + * 코드 생성 + * @param {boolean} exec 실행여부 + */ + PandasPackage.prototype.generateCode = function(addCell, exec) { + + var sbCode = new sb.StringBuilder(); + + // 코드 생성 + var codeValue = $(this.wrapSelector('#i0')).val(); + var returnValue = $(this.wrapSelector('#o0')).val(); + if (returnValue && returnValue != '') { + sbCode.appendFormat('{0} = ', returnValue); + } + sbCode.append(codeValue); + + + if (addCell) this.cellExecute(sbCode.toString(), exec); + + return sbCode.toString(); + } + + return { + initOption: initOption + }; +}); \ No newline at end of file
{4}
{4}{0}