@@ -87,7 +87,8 @@ define([
8787 { id : 'add_row' , label : 'Add row' , selection : FRAME_SELECT_TYPE . NONE , menuType : FRAME_EDIT_TYPE . ADD_ROW } ,
8888 { id : 'delete' , label : 'Delete' , selection : FRAME_SELECT_TYPE . MULTI , menuType : FRAME_EDIT_TYPE . DROP } ,
8989 { id : 'rename' , label : 'Rename' , selection : FRAME_SELECT_TYPE . NONE , menuType : FRAME_EDIT_TYPE . RENAME } ,
90- { id : 'asType' , label : 'As type' , selection : FRAME_SELECT_TYPE . NONE , axis : FRAME_AXIS . COLUMN , menuType : FRAME_EDIT_TYPE . AS_TYPE } ,
90+ { id : 'as_type' , label : 'As type' , selection : FRAME_SELECT_TYPE . NONE , axis : FRAME_AXIS . COLUMN , menuType : FRAME_EDIT_TYPE . AS_TYPE } ,
91+ { id : 'to_datetime' , label : 'To datetime' , selection : FRAME_SELECT_TYPE . SINGLE , axis : FRAME_AXIS . COLUMN , menuType : FRAME_EDIT_TYPE . TO_DATETIME } ,
9192 { id : 'replace' , label : 'Replace' , selection : FRAME_SELECT_TYPE . SINGLE , axis : FRAME_AXIS . COLUMN , menuType : FRAME_EDIT_TYPE . REPLACE } ,
9293 { id : 'discretize' , label : 'Discretize' , selection : FRAME_SELECT_TYPE . SINGLE , axis : FRAME_AXIS . COLUMN , numeric_only : true , menuType : FRAME_EDIT_TYPE . DISCRETIZE }
9394 ]
@@ -618,6 +619,7 @@ define([
618619 case FRAME_EDIT_TYPE . RENAME :
619620 case FRAME_EDIT_TYPE . REPLACE :
620621 case FRAME_EDIT_TYPE . AS_TYPE :
622+ case FRAME_EDIT_TYPE . TO_DATETIME :
621623 case FRAME_EDIT_TYPE . DISCRETIZE :
622624 case FRAME_EDIT_TYPE . DATA_SHIFT :
623625 case FRAME_EDIT_TYPE . SORT_INDEX :
@@ -1106,6 +1108,73 @@ define([
11061108 $ ( that . wrapSelector ( '.vp-inner-popup-fill-row' ) ) . hide ( ) ;
11071109 }
11081110 } ) ;
1111+ } else if ( menuType === FRAME_EDIT_TYPE . TO_DATETIME ) {
1112+ // bind event for selecting format
1113+ $ ( this . wrapSelector ( '.vp-inner-popup-todt-format' ) ) . on ( 'change' , function ( ) {
1114+ let format = $ ( this ) . val ( ) ;
1115+ if ( format === 'auto' ) {
1116+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-dayfirst' ) ) . prop ( 'disabled' , false ) ;
1117+ } else {
1118+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-dayfirst' ) ) . prop ( 'disabled' , true ) ;
1119+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-dayfirst' ) ) . val ( '' ) ;
1120+ }
1121+
1122+ if ( format === 'typing' ) {
1123+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-format-typing' ) ) . prop ( 'disabled' , false ) ;
1124+ } else {
1125+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-format-typing' ) ) . prop ( 'disabled' , true ) ;
1126+ }
1127+ } ) ;
1128+
1129+ // bind event for checking add column
1130+ $ ( this . wrapSelector ( '.vp-inner-popup-todt-use-addcol' ) ) . on ( 'change' , function ( ) {
1131+ let checked = $ ( this ) . prop ( 'checked' ) ;
1132+ if ( checked === true ) {
1133+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-addcol-box' ) ) . show ( ) ;
1134+ } else {
1135+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-addcol-box' ) ) . hide ( ) ;
1136+ }
1137+ } ) ;
1138+
1139+ // Add column set event
1140+ $ ( this . wrapSelector ( '.vp-inner-popup-todt-addcol' ) ) . on ( 'click' , function ( ) {
1141+ let dateTypeList = [ // df[col].dt[{dateType}]
1142+ { label : 'Year' , value : 'year' } ,
1143+ { label : 'Month' , value : 'month' } ,
1144+ { label : 'Day' , value : 'day' } ,
1145+ { label : 'Date' , value : 'date' } ,
1146+ { label : 'DayOfWeek' , value : 'dayofweek' } ,
1147+ { label : 'DayOfYear' , value : 'dayofyear' } ,
1148+ { label : 'DaysInMonth' , value : 'daysinmonth' } ,
1149+ { label : 'Quarter' , value : 'quarter' } ,
1150+ { label : 'Time' , value : 'time' } ,
1151+ { label : 'Hour' , value : 'hour' } ,
1152+ { label : 'Minute' , value : 'minute' } ,
1153+ { label : 'Second' , value : 'second' } ,
1154+ { label : 'Nanosecond' , value : 'nanosecond' } ,
1155+ ] ;
1156+ let dateTypeOptionTag = new com_String ( ) ;
1157+ dateTypeList . forEach ( opt => {
1158+ dateTypeOptionTag . appendFormat ( '<option value="{0}">{1}</option>' , opt . value , opt . label ) ;
1159+ } ) ;
1160+
1161+ let addColItemTag = $ ( `<div class="vp-inner-popup-todt-addcol-item">
1162+ <input type="text" class="vp-input vp-inner-popup-todt-addcol-colname" placeholder="Type column name" />
1163+ <select class="vp-select vp-inner-popup-todt-addcol-type">
1164+ ${ dateTypeOptionTag . toString ( ) }
1165+ </select>
1166+ <span class="vp-icon-close-small vp-inner-popup-todt-addcol-del mt5 vp-cursor"></span>
1167+ </div>` ) ;
1168+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-addcol-content' ) ) . append ( addColItemTag ) ;
1169+ $ ( addColItemTag ) [ 0 ] . scrollIntoView ( ) ;
1170+
1171+ // bind event for deleting
1172+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-addcol-del' ) ) . off ( 'click' ) ;
1173+ $ ( that . wrapSelector ( '.vp-inner-popup-todt-addcol-del' ) ) . on ( 'click' , function ( ) {
1174+ // delete item
1175+ $ ( this ) . closest ( '.vp-inner-popup-todt-addcol-item' ) . remove ( ) ;
1176+ } ) ;
1177+ } ) ;
11091178 }
11101179
11111180 }
@@ -2113,6 +2182,75 @@ define([
21132182 return content . toString ( ) ;
21142183 }
21152184
2185+ renderToDatetime ( ) {
2186+ var content = new com_String ( ) ;
2187+ let formatList = [
2188+ { label : 'Auto' , value : 'auto' } ,
2189+ { label : 'Year' , value : '%Y' } ,
2190+ { label : 'Month' , value : '%m' } ,
2191+ { label : 'Day' , value : '%d' } ,
2192+ { label : 'Day Of Week' , value : '%w' } ,
2193+ { label : '%Y/%m/%d' , value : '%Y/%m/%d' } ,
2194+ { label : '%Y-%m-%d' , value : '%Y-%m-%d' } ,
2195+ { label : '%d/%m/%Y' , value : '%d/%m/%Y' } ,
2196+ { label : '%d-%m-%Y' , value : '%d-%m-%Y' } ,
2197+ { label : 'Typing' , value : 'typing' } ,
2198+ ] ;
2199+ let formatOptionTag = new com_String ( ) ;
2200+ formatList . forEach ( opt => {
2201+ formatOptionTag . appendFormat ( '<option value="{0}">{1}</option>' , opt . value , opt . label ) ;
2202+ } ) ;
2203+
2204+ content . appendFormat ( `<div class="vp-inner-popup-todt vp-grid-box">
2205+ <div class="vp-grid-col-110">
2206+ <label>Target column</label>
2207+ <input type="text" class="vp-input" value="{0}" readonly />
2208+ </div>
2209+ <div class="vp-grid-col-110">
2210+ <label>Format</label>
2211+ <div>
2212+ <select class="vp-inner-popup-todt-format">
2213+ {1}
2214+ </select>
2215+ <input type="text" class="vp-input vp-inner-popup-todt-format-typing" value="" placeholder="Type format" disabled/>
2216+ </div>
2217+ </div>
2218+ <div class="vp-grid-col-110">
2219+ <label>Day first</label>
2220+ <select class="vp-inner-popup-todt-dayfirst">
2221+ <option value="">Select option...</option>
2222+ <option value="True">True</option>
2223+ <option value="False">False</option>
2224+ </select>
2225+ </div>
2226+ <hr style="margin: 5px 0;"/>
2227+ <div>
2228+ <label>
2229+ <input type="checkbox" class="vp-inner-popup-todt-use-addcol" />
2230+ <span>
2231+ Add column with date type
2232+ </span>
2233+ </label>
2234+ </div>
2235+ <div class="vp-inner-popup-todt-addcol-box vp-grid-border-box" style="display: none;">
2236+ <div class="vp-inner-popup-todt-addcol-head">
2237+ <label>New column name</label>
2238+ <label>Date type</label>
2239+ <label></label>
2240+ </div>
2241+ <div class="vp-inner-popup-todt-addcol-content vp-scrollbar">
2242+
2243+ </div>
2244+ <button class="vp-button vp-inner-popup-todt-addcol">+ Add column</button>
2245+ </div>
2246+ </div>
2247+ ` , this . state . selected [ 0 ] . label , formatOptionTag . toString ( ) , ) ;
2248+
2249+ // set content
2250+ $ ( this . wrapSelector ( '.vp-inner-popup-body' ) ) . html ( content . toString ( ) ) ;
2251+ return content . toString ( ) ;
2252+ }
2253+
21162254 renderFillNAPage ( ) {
21172255 var content = new com_String ( ) ;
21182256 content . appendFormatLine ( '<div class="{0}">' , 'vp-inner-popup-fillna-page' ) ;
@@ -2454,6 +2592,11 @@ define([
24542592 title = 'Convert type' ;
24552593 content = this . renderAsType ( ) ;
24562594 break ;
2595+ case FRAME_EDIT_TYPE . TO_DATETIME :
2596+ title = 'Convert to datetime' ;
2597+ size = { width : 500 , height : 450 } ;
2598+ content = this . renderToDatetime ( ) ;
2599+ break ;
24572600 case FRAME_EDIT_TYPE . FILL_NA :
24582601 title = 'Fill NA' ;
24592602 content = this . renderFillNAPage ( ) ;
@@ -2823,6 +2966,22 @@ define([
28232966 }
28242967 } ) ;
28252968 break ;
2969+ case FRAME_EDIT_TYPE . TO_DATETIME :
2970+ content [ 'format' ] = $ ( this . wrapSelector ( '.vp-inner-popup-todt-format' ) ) . val ( ) ;
2971+ content [ 'format_typing' ] = $ ( this . wrapSelector ( '.vp-inner-popup-todt-format-typing' ) ) . val ( ) ;
2972+ content [ 'dayfirst' ] = $ ( this . wrapSelector ( '.vp-inner-popup-todt-dayfirst' ) ) . val ( ) ;
2973+ content [ 'use_addcol' ] = $ ( this . wrapSelector ( '.vp-inner-popup-todt-use-addcol' ) ) . prop ( 'checked' ) ;
2974+ var colList = [ ] ;
2975+ var addcolItemTags = $ ( this . wrapSelector ( '.vp-inner-popup-todt-addcol-item' ) ) ;
2976+ addcolItemTags && addcolItemTags . each ( ( idx , tag ) => {
2977+ let colName = $ ( tag ) . find ( '.vp-inner-popup-todt-addcol-colname' ) . val ( ) ;
2978+ let dateType = $ ( tag ) . find ( '.vp-inner-popup-todt-addcol-type' ) . val ( ) ;
2979+ if ( colName !== '' && dateType !== '' ) {
2980+ colList . push ( { colName : colName , dateType : dateType } ) ;
2981+ }
2982+ } ) ;
2983+ content [ 'collist' ] = colList ;
2984+ break ;
28262985 case FRAME_EDIT_TYPE . DISCRETIZE :
28272986 content [ 'input' ] = $ ( this . wrapSelector ( '.vp-inner-popup-input' ) ) . val ( ) ;
28282987 content [ 'inputastext' ] = $ ( this . wrapSelector ( '.vp-inner-popup-inputastext' ) ) . prop ( 'checked' ) ;
@@ -3343,6 +3502,31 @@ define([
33433502 } ) ;
33443503 code . appendFormat ( "{0} = {1}.astype({{2}})" , tempObj , tempObj , astypeStr . toString ( ) ) ;
33453504 break ;
3505+ case FRAME_EDIT_TYPE . TO_DATETIME :
3506+ code . appendFormat ( "{0}[{1}] = pd.to_datetime({2}[{3}]" , tempObj , selectedName , tempObj , selectedName ) ;
3507+ let optionList = [ ] ;
3508+ if ( content [ 'format' ] === 'auto' ) {
3509+ if ( content [ 'dayfirst' ] !== '' ) {
3510+ optionList . push ( `dayfirst=${ content [ 'dayfirst' ] } ` ) ;
3511+ }
3512+ } else if ( content [ 'format' ] === 'typing' ) {
3513+ if ( content [ 'format_typing' ] !== '' ) {
3514+ optionList . push ( `format='${ content [ 'format_typing' ] } '` ) ;
3515+ }
3516+ } else {
3517+ optionList . push ( `format='${ content [ 'format' ] } '` ) ;
3518+ }
3519+ if ( optionList . length > 0 ) {
3520+ code . appendFormat ( ', {0}' , optionList . join ( ', ' ) ) ;
3521+ }
3522+ code . append ( ')' ) ;
3523+ if ( content [ 'use_addcol' ] === true && content [ 'collist' ] . length > 0 ) {
3524+ content [ 'collist' ] . forEach ( obj => {
3525+ code . appendLine ( ) ;
3526+ code . appendFormat ( "{0}['{1}'] = {2}[{3}].dt.{4}" , tempObj , obj . colName , tempObj , selectedName , obj . dateType ) ;
3527+ } ) ;
3528+ }
3529+ break ;
33463530 case FRAME_EDIT_TYPE . DISCRETIZE :
33473531 let newColumn = com_util . convertToStr ( content [ 'input' ] , content [ 'inputastext' ] ) ;
33483532 let method = content [ 'type' ] ;
@@ -3437,7 +3621,7 @@ define([
34373621 var indexList = data . index ;
34383622 var dataList = data . data ;
34393623
3440- columnList = columnList . map ( col => { return { label : col . label , type : col . dtype , code : col . value } } ) ;
3624+ columnList = columnList . map ( col => { return { label : col . label , type : col . dtype , code : col . value , isNumeric : col . is_numeric } } ) ;
34413625 indexList = indexList . map ( idx => { return { label : idx , code : idx } } ) ;
34423626
34433627 if ( ! more ) {
@@ -3453,6 +3637,12 @@ define([
34533637 while ( colIdx < columnList . length ) {
34543638 let col = columnList [ colIdx ] ;
34553639 let colCode = col . code . slice ( 0 , colLevIdx + 1 ) . join ( ',' ) ;
3640+ var colIcon = '' ;
3641+ if ( col . isNumeric === true ) {
3642+ colIcon = '<span class="vp-fe-table-column-isnumeric vp-icon-numeric" title="Numeric column"></span>' ;
3643+ } else {
3644+ colIcon = '<span class="vp-fe-table-column-isnumeric vp-icon-non-numeric" title="Non-numeric column"></span>' ;
3645+ }
34563646 let nextCol = columnList [ colIdx + 1 ] ;
34573647 if ( nextCol && nextCol . code . slice ( 0 , colLevIdx + 1 ) . join ( ',' ) === colCode ) {
34583648 colSpan ++ ;
@@ -3467,8 +3657,8 @@ define([
34673657 } else {
34683658 colClass = VP_FE_TABLE_COLUMN_GROUP ;
34693659 }
3470- table . appendFormatLine ( '<th data-code="({0})" data-axis="{1}" data-type="{2}" data-parent="{3}" data-label="{4}" class="{5} {6}" colspan="{7}">{8}</th>'
3471- , colCode , FRAME_AXIS . COLUMN , col . type , col . label [ colLevIdx - 1 ] , col . label [ colLevIdx ] , colClass , selected , colSpan , col . label [ colLevIdx ] ) ;
3660+ table . appendFormatLine ( '<th data-code="({0})" data-axis="{1}" data-type="{2}" data-parent="{3}" data-label="{4}" class="{5} {6}" colspan="{7}">{8}{9} </th>'
3661+ , colCode , FRAME_AXIS . COLUMN , col . type , col . label [ colLevIdx - 1 ] , col . label [ colLevIdx ] , colClass , selected , colSpan , colIcon , col . label [ colLevIdx ] ) ;
34723662 colSpan = 1 ;
34733663 }
34743664 colIdx ++ ;
@@ -3487,12 +3677,18 @@ define([
34873677 table . appendLine ( '<tr><th></th>' ) ;
34883678 columnList && columnList . forEach ( col => {
34893679 var colCode = col . code ;
3680+ var colIcon = '' ;
3681+ if ( col . isNumeric === true ) {
3682+ colIcon = '<span class="vp-fe-table-column-isnumeric vp-icon-numeric" title="Numeric column"></span>' ;
3683+ } else {
3684+ colIcon = '<span class="vp-fe-table-column-isnumeric vp-icon-non-numeric" title="Non-numeric column"></span>' ;
3685+ }
34903686 var colClass = '' ;
34913687 if ( that . state . axis == FRAME_AXIS . COLUMN && that . state . selected . map ( col => col . code ) . includes ( colCode ) ) {
34923688 colClass = 'selected' ;
34933689 }
3494- table . appendFormatLine ( '<th data-code="{0}" data-axis="{1}" data-type="{2}" data-label="{3}" class="{4} {5}">{6}</th>'
3495- , colCode , FRAME_AXIS . COLUMN , col . type , col . label , VP_FE_TABLE_COLUMN , colClass , col . label ) ;
3690+ table . appendFormatLine ( '<th data-code="{0}" data-axis="{1}" data-type="{2}" data-label="{3}" class="{4} {5}">{6}{7} </th>'
3691+ , colCode , FRAME_AXIS . COLUMN , col . type , col . label , VP_FE_TABLE_COLUMN , colClass , colIcon , col . label ) ;
34963692 } ) ;
34973693 // // add column
34983694 table . appendFormatLine ( '<th class="{0}"><div class="{1}"></div></th>' , VP_FE_ADD_COLUMN , 'vp-icon-plus' ) ;
@@ -3713,6 +3909,7 @@ define([
37133909 DROP : 3 ,
37143910 RENAME : 2 ,
37153911 AS_TYPE : 10 ,
3912+ TO_DATETIME : 19 ,
37163913 REPLACE : 9 ,
37173914 DISCRETIZE : 15 ,
37183915
0 commit comments