diff --git a/css/file_io/fileio.css b/css/file_io/fileio.css index 72e5d314..84f7b9b7 100644 --- a/css/file_io/fileio.css +++ b/css/file_io/fileio.css @@ -9,4 +9,8 @@ #vp_fileioPage .vp-fileio-body { padding: 5px; margin-top: 10px; +} + +.vp-option-table { + } \ No newline at end of file diff --git a/css/file_io/udf.css b/css/file_io/udf.css index 061ff199..50e47069 100644 --- a/css/file_io/udf.css +++ b/css/file_io/udf.css @@ -1,5 +1,6 @@ /* udf editor - CodeMirror */ #vp-wrapper .vp-udf-page .CodeMirror { border: 1px solid silver; } +#vp-wrapper .vp-udf-page .CodeMirror.CodeMirror-focused { border: 1px solid var(--hightlight-color); } #vp-wrapper .vp-udf-page .CodeMirror-empty { outline: 1px solid #c22; } #vp-wrapper .vp-udf-page .CodeMirror-empty.CodeMirror-focused { outline: none; } #vp-wrapper .vp-udf-page .CodeMirror pre.CodeMirror-placeholder { color: #999; } @@ -7,7 +8,7 @@ #vp-wrapper .vp-udf-page .CodeMirror-scroll { min-height: 80px; max-height: 250px;} /* udf option header */ -.vp-option-header { +/* .vp-option-header { padding-bottom: 3px; } .vp-option-header label { @@ -18,10 +19,10 @@ } .vp-option-header button { width: 70px; -} +} */ /* udf list table */ -#vp_udfList tr:not(:first-child):hover, +/* #vp_udfList tr:not(:first-child):hover, #vp_udfList tr.selected { color: var(--font-hightlight); background-color: #F5F5F5; @@ -39,10 +40,10 @@ text-overflow: ellipsis; width: 100%; overflow: hidden; -} +} */ /* code td 긴 문자열 생략 */ -.vp-udf-code, +/* .vp-udf-code, .vp-udf-code pre { text-overflow: ellipsis; overflow: hidden; @@ -53,15 +54,15 @@ background: #ffffff00; border: 0px; -} +} */ /* 새로고침 버튼 */ -#vp_udfRefresh { +/* #vp_udfRefresh { padding: 5px; } #vp_udfRefresh:hover { cursor: pointer; -} +} */ /* 삭제 버튼 */ .vp-del-col { @@ -243,6 +244,9 @@ border: 0.25px solid var(--border-gray-color); box-sizing: border-box; } +.vp-sn-item-header.selected { + background: #F5F5F5; +} .vp-sn-item-header .vp-sn-indicator { display: inline-block; cursor: pointer; @@ -255,18 +259,17 @@ .vp-sn-item-header .vp-sn-indicator.open { background-image: url(../../resource/chevron_big_down.svg) !important; } -.vp-sn-item-title { +#vp_udfPage .vp-sn-item-header input.vp-sn-item-title { width: calc(100% - 80px); outline: none; - border: 0.5px solid white !important; + background: transparent; + border: 0.5px solid transparent; } -.vp-sn-item.selected .vp-sn-item-title { - background: #F5F5F5; +#vp_udfPage .vp-sn-item-header.selected input.vp-sn-item-title { color: var(--font-hightlight); } -.vp-sn-item-title:focus { +#vp_udfPage .vp-sn-item-header input.vp-sn-item-title:focus { transition: 0.7s; - border: 1px solid #FFCF73; border: 0.5px solid var(--hightlight-color) !important; } .vp-sn-imported-item { diff --git a/resource/snippets/run.svg b/resource/snippets/run.svg new file mode 100644 index 00000000..8739260b --- /dev/null +++ b/resource/snippets/run.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/api_block/blockContainer.js b/src/api_block/blockContainer.js index 7775c383..154200f6 100644 --- a/src/api_block/blockContainer.js +++ b/src/api_block/blockContainer.js @@ -1835,6 +1835,7 @@ define([ if (Object.keys(loaded).includes('initOption')) { loaded.initOption(function(funcJS) { that.appsMenu = new popupPage(funcJS, 'vp_appsCode'); + funcJS.wrapSelector = that.appsMenu.wrapSelector; // library page $(vpCommon.wrapSelector(vpCommon.formatString("#{0}", vpConst.OPTION_GREEN_ROOM), vpCommon.formatString(".{0}", vpConst.API_OPTION_PAGE))).each(function() { that.appsMenu.open({ diff --git a/src/api_block/init.js b/src/api_block/init.js index 6af645af..58a6b067 100644 --- a/src/api_block/init.js +++ b/src/api_block/init.js @@ -713,7 +713,7 @@ define([ */ $(document).on("fileReadSelected.fileNavigation", function(e) { // 선택 파일 확장자가 노트 세이브 파일인 경우만 동작 - if (e.path.substring(e.path.lastIndexOf(".") + 1) === vpConst.VP_NOTE_EXTENSION) { + if (e.file.substring(e.file.lastIndexOf(".") + 1) === vpConst.VP_NOTE_EXTENSION) { openNotePageAction_newVersion(); } }); @@ -723,7 +723,7 @@ define([ */ $(document).on("fileSaveSelected.fileNavigation", function(e) { // 선택 파일 확장자가 노트 세이브 파일인 경우만 동작 - if (e.path.substring(e.path.lastIndexOf(".") + 1) === vpConst.VP_NOTE_EXTENSION) { + if (e.file.substring(e.file.lastIndexOf(".") + 1) === vpConst.VP_NOTE_EXTENSION) { var selectedPath = $(vpCommon.wrapSelector(vpCommon.formatString("#{0}", vpConst.VP_NOTE_REAL_FILE_PATH))).val(); var saveFileName = selectedPath.substring(selectedPath.lastIndexOf("/") + 1); // FIXME: 여기부분 수정해야 함 diff --git a/src/common/vpPopupPage.js b/src/common/vpPopupPage.js index 04a6f65c..9e6bc313 100644 --- a/src/common/vpPopupPage.js +++ b/src/common/vpPopupPage.js @@ -67,12 +67,15 @@ define([ page.appendLine(''); // body end // button box - page.appendFormatLine('
', VP_PP_BUTTON_BOX); - page.appendFormatLine('' - , VP_PP_BUTTON_CANCEL, 'Cancel'); - page.appendFormatLine('' - , VP_PP_BUTTON_APPLY, 'Apply'); - page.appendLine('
'); + // Snippets menu don't use buttons + if (title != 'Snippets') { + page.appendFormatLine('
', VP_PP_BUTTON_BOX); + page.appendFormatLine('' + , VP_PP_BUTTON_CANCEL, 'Cancel'); + page.appendFormatLine('' + , VP_PP_BUTTON_APPLY, 'Apply'); + page.appendLine('
'); + } page.appendLine(''); // container end page.appendLine(''); // VP_PP end @@ -100,6 +103,18 @@ define([ $(this.wrapSelector()).remove(); } + PopupPage.prototype.apply = function() { + if (this.pageThis) { + var code = this.pageThis.generateCode(false, false); + $(vpCommon.wrapSelector('#' + this.targetId)).val(code); + $(vpCommon.wrapSelector('#' + this.targetId)).trigger({ + type: 'popup_apply', + title: this.config.title, + code: code + }); + } + } + PopupPage.prototype.bindEvent = function() { var that = this; @@ -115,15 +130,7 @@ define([ // click apply $(document).on('click', this.wrapSelector('.' + VP_PP_BUTTON_APPLY), function() { - if (that.pageThis) { - var code = that.pageThis.generateCode(false, false); - $(vpCommon.wrapSelector('#' + that.targetId)).val(code); - $(vpCommon.wrapSelector('#' + that.targetId)).trigger({ - type: 'popup_apply', - title: that.config.title, - code: code - }); - } + that.apply(); that.close(); }); } diff --git a/src/file_io/fileio.js b/src/file_io/fileio.js index cfb28a2c..24e1816a 100644 --- a/src/file_io/fileio.js +++ b/src/file_io/fileio.js @@ -172,6 +172,7 @@ define([ */ PandasPackage.prototype.initHtml = function() { this.showFunctionTitle(); + this.loadCss(Jupyter.notebook.base_url + vpConst.BASE_PATH + vpConst.STYLE_PATH + "pandas/commonPandas.css"); this.loadCss(Jupyter.notebook.base_url + vpConst.BASE_PATH + vpConst.STYLE_PATH + "file_io/fileio.css"); this.bindOptions(); @@ -217,6 +218,20 @@ define([ var selectedType = this.fileState[pageType]['selectedType']; var package = { ...libPandas._PANDAS_FUNCTION[fileTypeObj[selectedType]] }; this.fileState[pageType].package = package; + this.state.fileExtension = that.fileExtensions[selectedType]; + this.fileResultState = { + ...this.fileState[pageType].fileResultState + }; + + if (pageType == 'Write') { + if (selectedType == 'json') { + this.fileResultState.pathInputId = this.wrapSelector(prefix + '#path_or_buf'); + } + if (selectedType == 'pickle') { + this.fileResultState.pathInputId = this.wrapSelector(prefix + '#path'); + } + } + // render interface pdGen.vp_showInterfaceOnPage(this, this.wrapSelector('#vp_file' + pageType), package); @@ -238,38 +253,34 @@ define([ $(this.wrapSelector(prefix + '#fileType')).change(function() { var value = $(this).val(); that.fileState[pageType].selectedType = value; - that.state.fileExtension = that.fileExtensions[value]; - that.fileResultState = { - ...that.fileState[pageType].fileResultState - }; - - if (pageType == 'Write') { - if (value == 'json') { - that.fileResultState.pathInputId = that.wrapSelector(prefix + '#path_or_buf'); - } - if (value == 'pickle') { - that.fileResultState.pathInputId = that.wrapSelector(prefix + '#path'); - } - } // reload that.renderPage(pageType); }); // 파일 네비게이션 버튼 추가 - if (pageType == 'Write' && selectedType == 'json') { - $(this.fileState[pageType]['fileResultState']['pathInputId']).parent().html( - vpCommon.formatString('
' - , vpConst.FILE_BROWSER_INPUT_BUTTON) - ); - } else if (pageType == 'Write' && selectedType == 'pickle') { - $(this.fileState[pageType]['fileResultState']['pathInputId']).parent().html( - vpCommon.formatString('
' - , vpConst.FILE_BROWSER_INPUT_BUTTON) - ); + if (pageType == 'Write') { + if (selectedType == 'json') { + $(prefix + '#path_or_buf').parent().html( + vpCommon.formatString('
' + , vpConst.FILE_BROWSER_INPUT_BUTTON) + ); + } else if (selectedType == 'pickle') { + $(prefix + '#path').parent().html( + vpCommon.formatString('
' + , vpConst.FILE_BROWSER_INPUT_BUTTON) + ); + } else { + $(this.fileState[pageType]['fileResultState']['pathInputId']).parent().html( + vpCommon.formatString('
' + , 'i1' + , vpConst.FILE_BROWSER_INPUT_BUTTON) + ); + } } else { $(this.fileState[pageType]['fileResultState']['pathInputId']).parent().html( - vpCommon.formatString('
' + vpCommon.formatString('
' + , 'i0' , vpConst.FILE_BROWSER_INPUT_BUTTON) ); } diff --git a/src/file_io/udf.html b/src/file_io/udf.html index 4a72e949..22e35b98 100644 --- a/src/file_io/udf.html +++ b/src/file_io/udf.html @@ -1,5 +1,5 @@ -
+
diff --git a/src/file_io/udf.js b/src/file_io/udf.js index 2d34bdff..e53d9367 100644 --- a/src/file_io/udf.js +++ b/src/file_io/udf.js @@ -81,6 +81,9 @@ define([ this.importedList = []; this.title_no = 0; + // double click setter + this.clicked = 0; + // file navigation : state 데이터 목록 this.state = { paramData:{ @@ -138,22 +141,22 @@ define([ var that = this; // toggle item codebox - $(document).on('click', this.wrapSelector('.vp-sn-item-header .vp-sn-indicator'), function() { - var parent = $(this).parent(); - var hasOpen = $(this).hasClass('open'); - // hide all codebox - $(that.wrapSelector('.vp-sn-indicator')).removeClass('open'); - $(that.wrapSelector('.vp-sn-item-code')).hide(); + // $(document).on('click', this.wrapSelector('.vp-sn-item-header .vp-sn-indicator'), function() { + // var parent = $(this).parent(); + // var hasOpen = $(this).hasClass('open'); + // // hide all codebox + // $(that.wrapSelector('.vp-sn-indicator')).removeClass('open'); + // $(that.wrapSelector('.vp-sn-item-code')).hide(); - if (!hasOpen) { - // show code - $(this).addClass('open'); - $(parent).parent().find('.vp-sn-item-code').show(); - } else { - // hide code - $(parent).parent().find('.vp-sn-item-code').hide(); - } - }); + // if (!hasOpen) { + // // show code + // $(this).addClass('open'); + // $(parent).parent().find('.vp-sn-item-code').show(); + // } else { + // // hide code + // $(parent).parent().find('.vp-sn-item-code').hide(); + // } + // }); // menu popup $(document).on('click', this.wrapSelector('.vp-sn-menu'), function(evt) { @@ -285,34 +288,111 @@ define([ that.title_no += 1; }); + // item header click (toggle & select item) & double click (edit title) + $(document).on('click', this.wrapSelector('.vp-sn-item-header'), function(evt) { + var thisHeader = this; + that.clicked++; + if (that.clicked == 1) { + setTimeout(function(){ + if(that.clicked > 1) { + // double click + // enable input + $(thisHeader).find('.vp-sn-item-title').prop('disabled', false); + $(thisHeader).find('.vp-sn-item-title').focus(); + + } + // single click + // select item + // remove selection + $(that.wrapSelector('.vp-sn-item-header')).removeClass('selected'); + // select item + $(thisHeader).addClass('selected'); + + // toggle item + var parent = $(thisHeader).parent(); + var indicator = $(thisHeader).find('.vp-sn-indicator'); + var hasOpen = $(indicator).hasClass('open'); + // hide all codebox + $(that.wrapSelector('.vp-sn-indicator')).removeClass('open'); + $(that.wrapSelector('.vp-sn-item-code')).hide(); + + if (that.clicked > 1 || !hasOpen) { + // show code + $(indicator).addClass('open'); + $(parent).find('.vp-sn-item-code').show(); + } else { + // hide code + $(parent).find('.vp-sn-item-code').hide(); + } + that.clicked = 0; + }, 200); + } + evt.stopPropagation(); + }); + + // prevent occuring header click event by clicking input + $(document).on('click', this.wrapSelector('.vp-sn-item-title'), function(evt) { + evt.stopPropagation(); + }); + // item title save - $(document).on('change', this.wrapSelector('.vp-sn-item-title'), function(evt) { + $(document).on('blur', this.wrapSelector('.vp-sn-item-title'), function(evt) { var prevTitle = $(this).closest('.vp-sn-item').data('title'); - var newTitle = $(this).val(); + var inputTitle = $(this).val(); - that.codemirrorList[prevTitle].save(); - var code = that.codemirrorList[prevTitle].getValue(); - // 기존 title 제거 - vpSetting.removeUserDefinedCode(prevTitle); - - // 새 title로 저장 - // save udf - var newTimestamp = new Date().getTime(); - var newSnippet = { [newTitle]: { code: code, timestamp: newTimestamp } }; - vpSetting.saveUserDefinedCode(newSnippet); + if (prevTitle == inputTitle) { + ; + } else { + // check duplicated + var titleList = Object.keys(that.codemirrorList); + var newTitle = inputTitle; + var dupNo = 0 + while(titleList.includes(newTitle)) { + dupNo += 1; + newTitle = inputTitle + '_' + dupNo; + } + + that.codemirrorList[prevTitle].save(); + var code = that.codemirrorList[prevTitle].getValue(); + // 기존 title 제거 + vpSetting.removeUserDefinedCode(prevTitle); + + // 새 title로 저장 + // save udf + var newTimestamp = new Date().getTime(); + var newSnippet = { [newTitle]: { code: code, timestamp: newTimestamp } }; + vpSetting.saveUserDefinedCode(newSnippet); + + // update title & codemirror + $(this).closest('.vp-sn-item-title').val(newTitle); + $(this).closest('.vp-sn-item').data('title', newTitle); + // update codemirror + that.codemirrorList[newTitle] = that.codemirrorList[prevTitle]; + delete that.codemirrorList[prevTitle]; + } - // update title & codemirror - $(this).closest('.vp-sn-item').data('title', newTitle); - // update codemirror - that.codemirrorList[newTitle] = that.codemirrorList[prevTitle]; - delete that.codemirrorList[prevTitle]; + // disable + $(this).prop('disabled', true); }); // item menu click $(document).on('click', this.wrapSelector('.vp-sn-item-menu-item'), function(evt) { var menu = $(this).data('menu'); var title = $(this).closest('.vp-sn-item').data('title'); - if (menu == 'duplicate') { + if (menu == 'run') { + var item = $(this).closest('.vp-sn-item'); + var title = $(item).data('title'); + + // get codemirror + that.codemirrorList[title].save(); + var code = that.codemirrorList[title].getValue(); + $(vpCommon.wrapSelector('#vp_appsCode')).val(code); + $(vpCommon.wrapSelector('#vp_appsCode')).trigger({ + type: 'popup_apply', + title: 'Snippets', + code: code + }); + } else if (menu == 'duplicate') { var dupNo = 1; var timestamp = new Date().getTime(); var dupTitle = title + '_dup' + dupNo; @@ -333,7 +413,7 @@ define([ var dupSnippet = { [dupTitle]: { code: code, timestamp: timestamp } }; vpSetting.saveUserDefinedCode(dupSnippet); - var tag = $(that.wrapSelector('.vp-sn-item-code textarea[data-title="' + dupTitle + '"]')); + var tag = $(that.wrapSelector('.vp-sn-item[data-title="' + dupTitle + '"] textarea')); that.bindCodeMirror(dupTitle, tag[0]); $(dupItem).find('.vp-sn-indicator').trigger('click'); @@ -417,7 +497,7 @@ define([ // export complete event $(document).on('snippetSaved.fileNavigation', this.wrapSelector('.vp-sn-filepath'), function(evt) { - var fileName = evt.path; + var fileName = evt.file; var selectedPath = $(this).val(); // get checked snippets @@ -489,11 +569,15 @@ define([ item.appendFormatLine('
', 'vp-sn-item', title, timestamp); item.appendFormatLine('
', 'vp-sn-item-header'); item.appendFormatLine('
', 'vp-sn-indicator'); - item.appendFormatLine('', 'vp-sn-item-title', title); + item.appendFormatLine('', 'vp-sn-item-title', title); if (hasImported) { item.appendFormatLine('', 'fa fa-circle vp-sn-imported-item'); } item.appendFormatLine('
', 'vp-sn-item-menu'); + item.appendFormatLine('
' + , 'vp-sn-item-menu-item', 'run', 'Run'); + item.appendFormatLine('', '/nbextensions/visualpython/resource/snippets/run.svg'); + item.appendLine('
'); item.appendFormatLine('
' , 'vp-sn-item-menu-item', 'duplicate', 'Duplicate'); item.appendFormatLine('', '/nbextensions/visualpython/resource/snippets/duplicate.svg'); @@ -595,6 +679,19 @@ define([ // save codemirror value to origin textarea // this.vp_userCode.save(); + // selected snippet + var selected = $(this.wrapSelector('.vp-sn-item-header.selected')); + if (selected) { + var item = $(selected).closest('.vp-sn-item'); + var title = $(item).data('title'); + + // get codemirror + this.codemirrorList[title].save(); + var code = this.codemirrorList[title].getValue(); + sbCode.append(code); + } + + if (addCell) this.cellExecute(sbCode.toString(), exec); return sbCode.toString(); diff --git a/src/matplotlib/plot.js b/src/matplotlib/plot.js index faaeffce..2f3cb15f 100644 --- a/src/matplotlib/plot.js +++ b/src/matplotlib/plot.js @@ -605,6 +605,8 @@ define([ // view button click - view little popup to show variable & details $(this.wrapSelector('.vp-select-data')).click(function(event) { var axes = $(this).data('axes'); + + var btnPos = $(this)[0].getBoundingClientRect(); if($(that.wrapSelector('#vp_varViewBox')).is(":hidden")) { // refresh variables @@ -612,12 +614,16 @@ define([ // set position var boxSize = { width: 280, height: 260 }; var boxPosition = { position: 'fixed', left: event.pageX - 20, top: event.pageY + 20 }; - if (event.pageX + boxSize.width > window.innerWidth) { - boxPosition.left = event.pageX - boxSize.width; - } - if (event.pageY + boxSize.height > window.innerHeight) { - boxPosition.top = event.pageY - boxSize.height - 20; - } + // if (event.pageX + boxSize.width > window.innerWidth) { + // boxPosition.left = event.pageX - boxSize.width; + // } + // if (event.pageY + boxSize.height > window.innerHeight) { + // boxPosition.top = event.pageY - boxSize.height - 20; + // } + + // set as center + boxPosition.left = 'calc(50% - 140px)' + boxPosition.top = 'calc(50% - 130px)' $('#vp_varViewBox').css({ ...boxPosition }); diff --git a/src/pandas/fileNavigation/renderer.js b/src/pandas/fileNavigation/renderer.js index 8dafcf76..6b352fed 100644 --- a/src/pandas/fileNavigation/renderer.js +++ b/src/pandas/fileNavigation/renderer.js @@ -394,29 +394,33 @@ define([ /** 최초의 path가 C:/Users/L.E.E/Desktop/Bit Python이라면, baseFolder는 Bit Python * 현재 이동한 시점의 path에서 baseFolder인 Bit Python가 존재하지 않을 때 */ + var pathInput = ''; + var fileInput = `${filePathStr}`; if (upDirectoryCount > 0 && currentDirStr.indexOf(baseFolder) === -1) { /** 2020년 12월 21일 single quote 삭제 */ - $(fileNavigationRendererThis.fileResultState.pathInputId).val(`${prefixUpDirectory}${relativeDirPath}${slashstr}${filePathStr}`); - $(fileNavigationRendererThis.fileResultState.fileInputId).val(`${filePathStr}`); - /** 현재 이동한 시점의 path에서 baseFolder인 Bit Python가 존재할 때 */ + pathInput = `${prefixUpDirectory}${relativeDirPath}${slashstr}${filePathStr}`; + /** 현재 이동한 시점의 path에서 baseFolder인 Bit Python가 존재할 때 */ } else { - $(fileNavigationRendererThis.fileResultState.pathInputId).val(`./${relativeDirPath}${slashstr}${filePathStr}`); - $(fileNavigationRendererThis.fileResultState.fileInputId).val(`${filePathStr}`); + pathInput = `./${relativeDirPath}${slashstr}${filePathStr}`; } + $(fileNavigationRendererThis.fileResultState.pathInputId).val(pathInput); + $(fileNavigationRendererThis.fileResultState.fileInputId).val(fileInput); // vpCommon.renderSuccessMessage(filePathStr + ' selection ' + 'completed'); /** 장안태 추가. 파일 선택 완료시 문서 이벤트 발동 */ if (fileNavigationState.getFileNavigationtype() === FILE_NAVIGATION_TYPE.SAVE_FILE) { $(document).trigger({ - type:"fileSaveSelected.fileNavigation", - path:`${filePathStr}` + type: "fileSaveSelected.fileNavigation", + file: fileInput, + path: pathInput }); } else { $(document).trigger({ - type:"fileReadSelected.fileNavigation", - path:`${filePathStr}` + type: "fileReadSelected.fileNavigation", + file: fileInput, + path: pathInput }); } @@ -425,7 +429,8 @@ define([ if (fileNavigationState.getFileNavigationtype() === FILE_NAVIGATION_TYPE.READ_IMG_FOR_MARKDOWN) { $(document).trigger({ type: fileNavigationState.getTriggerName(), - path: `${filePathStr}` + file: fileInput, + path: pathInput }) } @@ -433,14 +438,16 @@ define([ if (fileNavigationState.getFileNavigationtype() === FILE_NAVIGATION_TYPE.SAVE_SNIPPETS) { $(fileNavigationRendererThis.fileResultState.pathInputId).trigger({ type: 'snippetSaved.fileNavigation', - path:`${filePathStr}` + file: fileInput, + path: pathInput }); } /** Snippets 불러오기 후 이벤트 발동 */ if (fileNavigationState.getFileNavigationtype() === FILE_NAVIGATION_TYPE.READ_SNIPPETS) { $(fileNavigationRendererThis.fileResultState.pathInputId).trigger({ type: 'snippetRead.fileNavigation', - path:`${filePathStr}` + file: fileInput, + path: pathInput }); }