/**
* External dependencies
*/
import Charts from './Components/Charts.js';
import ChartSelect from './Components/ChartSelect.js';
import ChartRender from './Components/ChartRender.js';
import { CSVToArray, buildChartPopup, tryGetPublishedChartData } from './utils.js';
/**
* WordPress dependencies
*/
const { __ } = wp.i18n;
const {
apiFetch,
apiRequest
} = wp;
const {
Component,
Fragment
} = wp.element;
const {
Button,
ButtonGroup,
Dashicon,
Placeholder,
Notice,
Spinner
} = wp.components;
class Editor extends Component {
constructor() {
super( ...arguments );
this.getChart = this.getChart.bind( this );
this.editChart = this.editChart.bind( this );
this.editSettings = this.editSettings.bind( this );
this.editPermissions = this.editPermissions.bind( this );
this.readUploadedFile = this.readUploadedFile.bind( this );
this.editURL = this.editURL.bind( this );
this.editSchedule = this.editSchedule.bind( this );
this.editJSONSchedule = this.editJSONSchedule.bind( this );
this.editJSONURL = this.editJSONURL.bind( this );
this.editJSONHeaders = this.editJSONHeaders.bind( this );
this.editJSONRoot = this.editJSONRoot.bind( this );
this.editJSONPaging = this.editJSONPaging.bind( this );
this.JSONImportData = this.JSONImportData.bind( this );
this.editDatabaseSchedule = this.editDatabaseSchedule.bind( this );
this.databaseImportData = this.databaseImportData.bind( this );
this.uploadData = this.uploadData.bind( this );
this.getChartData = this.getChartData.bind( this );
this.editChartData = this.editChartData.bind( this );
this.updateChart = this.updateChart.bind( this );
this.createChart = this.createChart.bind( this );
this.state = {
/**
* Block Route Status
*
* home - Initial screen.
* showCharts - Display list of charts to pick.
* chartSelect - Chart selected.
* renderChart - Chart render.
*/
route: ( this.props.attributes.route ? this.props.attributes.route : 'home' ),
chart: null,
isModified: false,
isLoading: false,
isScheduled: false
};
}
async componentDidMount() {
// Fetch review again if block loaded after saving.
if ( this.props.attributes.id ) {
let result = await apiFetch({ path: `wp/v2/visualizer/${this.props.attributes.id}` }).catch( function( error ) {
});
if ( result ) {
this.setState({
chart: result['chart_data']
});
} else {
// if the chart is not found.
this.setState({
route: 'error'
});
}
}
}
async getChart( id ) {
await this.setState({
isLoading: 'getChart'
});
const chartDataRequest = await tryGetPublishedChartData( id );
if ( 'publish' !== chartDataRequest.chartStatus ) {
this.setState({ route: 'showCharts', isLoading: false });
this.props.setAttributes({ route: 'showCharts' });
return;
}
this.setState({
route: 'chartSelect',
chart: chartDataRequest.result['chart_data'],
isLoading: true,
isModified: true
});
this.props.setAttributes({
id,
route: 'chartSelect',
lazy: -1
});
}
editChart() {
this.setState({ route: 'chartSelect' });
this.props.setAttributes({ route: 'chartSelect' });
}
editSettings( settings ) {
let chart = { ...this.state.chart };
if ( '1' !== settings.pagination ) {
delete settings.pageSize;
}
chart['visualizer-settings'] = settings;
this.setState({
chart,
isModified: true
});
}
editPermissions( permissions ) {
let chart = { ...this.state.chart };
chart['visualizer-permissions'] = permissions;
this.setState({
chart,
isModified: true
});
}
readUploadedFile( e ) {
const fileTobeRead = e.current.files[0];
const fileReader = new FileReader();
fileReader.onload = () => {
const data = CSVToArray( fileReader.result );
this.editChartData( data, 'Visualizer_Source_Csv' );
};
fileReader.readAsText( fileTobeRead );
}
editURL( url ) {
let chart = { ...this.state.chart };
chart['visualizer-chart-url'] = url;
this.setState({ chart });
}
editSchedule( schedule ) {
let chart = { ...this.state.chart };
chart['visualizer-chart-schedule'] = schedule;
this.setState({
chart,
isModified: true
});
}
editJSONSchedule( schedule ) {
let chart = { ...this.state.chart };
chart['visualizer-json-schedule'] = schedule;
this.setState({
chart,
isModified: true
});
}
editJSONURL( url ) {
let chart = { ...this.state.chart };
chart['visualizer-json-url'] = url;
this.setState({ chart });
}
editJSONHeaders( headers ) {
let chart = { ...this.state.chart };
delete headers.username;
delete headers.password;
chart['visualizer-json-headers'] = headers;
this.setState({ chart });
}
editJSONRoot( root ) {
let chart = { ...this.state.chart };
chart['visualizer-json-root'] = root;
this.setState({ chart });
}
editJSONPaging( root ) {
let chart = { ...this.state.chart };
chart['visualizer-json-paging'] = root;
this.setState({ chart });
}
JSONImportData( name, series, data ) {
let chart = { ...this.state.chart };
chart['visualizer-source'] = name;
chart['visualizer-default-data'] = 0;
chart['visualizer-series'] = series;
chart['visualizer-data'] = data;
this.setState({
chart,
isModified: true
});
}
editDatabaseSchedule( schedule ) {
let chart = { ...this.state.chart };
chart['visualizer-db-schedule'] = schedule;
this.setState({
chart,
isModified: true
});
}
databaseImportData( query, name, series, data ) {
let chart = { ...this.state.chart };
chart['visualizer-source'] = name;
chart['visualizer-default-data'] = 0;
chart['visualizer-series'] = series;
chart['visualizer-data'] = data;
chart['visualizer-db-query'] = query;
this.setState({
chart,
isModified: true
});
}
uploadData( scheduled = false ) {
this.setState({
isLoading: 'uploadData',
isScheduled: scheduled
});
apiRequest({ path: `/visualizer/v1/upload-data?url=${this.state.chart['visualizer-chart-url']}`, method: 'POST' }).then(
( data ) => {
if ( 2 <= Object.keys( data ).length ) {
let chart = { ...this.state.chart };
chart['visualizer-source'] = 'Visualizer_Source_Csv_Remote';
chart['visualizer-default-data'] = 0;
chart['visualizer-series'] = data.series;
chart['visualizer-data'] = data.data;
let series = chart['visualizer-series'];
let settings = chart['visualizer-settings'];
let map = series;
let fieldName = 'series';
if ( 'pie' === chart['visualizer-chart-type']) {
map = chart['visualizer-data'];
fieldName = 'slices';
}
map.map( ( i, index ) => {
if ( 'pie' !== chart['visualizer-chart-type'] && 0 === index ) {
return;
}
const seriesIndex = 'pie' !== chart['visualizer-chart-type'] ? index - 1 : index;
if ( settings[fieldName][seriesIndex] === undefined ) {
settings[fieldName][seriesIndex] = {};
settings[fieldName][seriesIndex].temp = 1;
}
});
settings[fieldName] = settings[fieldName].filter( ( i, index ) => {
const length = 'pie' !== chart['visualizer-chart-type'] ? map.length - 1 : map.length;
return index < length;
});
chart['visualizer-settings'] = settings;
this.setState({
chart,
isModified: true,
isLoading: false
});
return data;
}
this.setState({
isLoading: false
});
},
( err ) => {
this.setState({
isLoading: false
});
return err;
}
);
}
async getChartData( id ) {
await this.setState({
isLoading: 'getChartData'
});
let result = await apiFetch({ path: `wp/v2/visualizer/${id}` });
let chart = { ...this.state.chart };
chart['visualizer-source'] = 'Visualizer_Source_Csv';
chart['visualizer-default-data'] = 0;
chart['visualizer-series'] = result['chart_data']['visualizer-series'];
chart['visualizer-data'] = result['chart_data']['visualizer-data'];
this.setState({
isLoading: false,
chart
});
}
editChartData( chartData, source ) {
let chart = { ...this.state.chart };
let series = [];
let settings = { ...chart['visualizer-settings'] };
let type = chart['visualizer-chart-type'];
chartData[0].map( ( i, index ) => {
series[index] = {
label: i,
type: chartData[1][index]
};
});
chartData.splice( 0, 2 );
let map = series;
let fieldName = 'series';
switch ( type ) {
case 'pie':
map = chartData;
fieldName = 'slices';
// pie charts are finicky about a number being a number
// and editing a number makes it a string
// so let's convert it back into a number.
chartData.map( ( i, index ) => {
switch ( series[1].type ) {
case 'number':
i[1] = parseFloat( i[1]);
break;
}
});
break;
case 'tabular':
// table charts are finicky about a boolean being a boolean
// and editing a boolean makes it a string
// so let's convert it back into a boolean.
chartData.map( ( i, index ) => {
series.map( ( seriesObject, seriesIndex ) => {
switch ( seriesObject.type ) {
case 'boolean':
if ( 'string' === typeof i[seriesIndex]) {
i[seriesIndex] = 'true' === i[seriesIndex];
}
break;
}
});
});
break;
}
map.map( ( i, index ) => {
if ( 'pie' !== type && 0 === index ) {
return;
}
const seriesIndex = 'pie' !== type ? index - 1 : index;
if ( Array.isArray( settings[fieldName]) && settings[fieldName][seriesIndex] === undefined ) {
settings[fieldName][seriesIndex] = {};
settings[fieldName][seriesIndex].temp = 1;
}
});
if ( Array.isArray( settings[fieldName]) ) {
settings[fieldName] = settings[fieldName].filter( ( i, index ) => {
const length = -1 >= [ 'pie', 'tabular', 'dataTable' ].indexOf( type ) ? map.length - 1 : map.length;
return index < length;
});
}
chart['visualizer-source'] = source;
chart['visualizer-default-data'] = 0;
chart['visualizer-data'] = chartData;
chart['visualizer-series'] = series;
chart['visualizer-settings'] = settings;
chart['visualizer-chart-url'] = '';
this.setState({
chart,
isModified: true,
isScheduled: false
});
}
updateChart() {
this.setState({ isLoading: 'updateChart' });
const data = this.state.chart;
if ( false === this.state.isScheduled ) {
data['visualizer-chart-schedule'] = '';
}
let dataChartStylingOption = 'series';
if ( 'pie' === data['visualizer-chart-type']) {
dataChartStylingOption = 'slices';
}
// no series for bubble and timeline charts.
if (
undefined !== data['visualizer-settings'][dataChartStylingOption] &&
-1 >= [ 'bubble', 'timeline' ].indexOf( data['visualizer-chart-type'])
) {
Object.keys( data['visualizer-settings'][dataChartStylingOption])
.map( i => {
if ( data['visualizer-settings'][dataChartStylingOption][i] !== undefined ) {
if ( data['visualizer-settings'][dataChartStylingOption][i].temp !== undefined ) {
delete data['visualizer-settings'][dataChartStylingOption][i].temp;
}
}
}
);
}
apiRequest({ path: `/visualizer/v1/update-chart?id=${ this.props.attributes.id }`, method: 'POST', data: data }).then(
( data ) => {
this.setState({
isLoading: false,
isModified: false
});
return data;
},
( err ) => {
return err;
}
);
}
/**
* Create a new chart via popup.
*
* @returns {void}
*/
async createChart() {
// Use the same popup like in Chart Library.
const createChartPopup = new ( buildChartPopup() )({
action: visualizerLocalize.createChart
});
// eslint-disable-next-line camelcase
window.send_to_editor = () => {
createChartPopup.close();
};
window.parent.addEventListener( 'message', ( event ) => {
if ( 'visualizer:mediaframe:close' === event.data ) {
createChartPopup.close();
} else if ( event.data.chartID ) {
const chartID = parseInt( event.data.chartID, 10 );
this.getChart( chartID );
}
}, false );
createChartPopup.open();
}
render() {
if ( 'error' === this.state.route ) {
return (