PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.7.6
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.7.6
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / classes / Visualizer / Gutenberg / src / Editor.js

Editor.js in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.7.6, at classes/Visualizer/Gutenberg/src/Editor.js

631 lines 16.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * External dependencies
3 */
4 import Charts from './Components/Charts.js';
5
6 import ChartSelect from './Components/ChartSelect.js';
7
8 import ChartRender from './Components/ChartRender.js';
9
10 import { CSVToArray } from './utils.js';
11
12 /**
13 * WordPress dependencies
14 */
15 const { __ } = wp.i18n;
16
17 const {
18 apiFetch,
19 apiRequest
20 } = wp;
21
22 const {
23 Component,
24 Fragment
25 } = wp.element;
26
27 const {
28 Button,
29 ButtonGroup,
30 Dashicon,
31 Placeholder,
32 Notice,
33 Spinner
34 } = wp.components;
35
36 class Editor extends Component {
37 constructor() {
38 super( ...arguments );
39
40 this.getChart = this.getChart.bind( this );
41 this.editChart = this.editChart.bind( this );
42 this.editSettings = this.editSettings.bind( this );
43 this.editPermissions = this.editPermissions.bind( this );
44 this.readUploadedFile = this.readUploadedFile.bind( this );
45 this.editURL = this.editURL.bind( this );
46 this.editSchedule = this.editSchedule.bind( this );
47 this.editJSONSchedule = this.editJSONSchedule.bind( this );
48 this.editJSONURL = this.editJSONURL.bind( this );
49 this.editJSONHeaders = this.editJSONHeaders.bind( this );
50 this.editJSONRoot = this.editJSONRoot.bind( this );
51 this.editJSONPaging = this.editJSONPaging.bind( this );
52 this.JSONImportData = this.JSONImportData.bind( this );
53 this.editDatabaseSchedule = this.editDatabaseSchedule.bind( this );
54 this.databaseImportData = this.databaseImportData.bind( this );
55 this.uploadData = this.uploadData.bind( this );
56 this.getChartData = this.getChartData.bind( this );
57 this.editChartData = this.editChartData.bind( this );
58 this.updateChart = this.updateChart.bind( this );
59
60 this.state = {
61
62 /**
63 * Block Route Status
64 *
65 * home - Initial screen.
66 * showCharts - Display list of charts to pick.
67 * chartSelect - Chart selected.
68 * renderChart - Chart render.
69 */
70 route: ( this.props.attributes.route ? this.props.attributes.route : 'home' ),
71 chart: null,
72 isModified: false,
73 isLoading: false,
74 isScheduled: false
75 };
76 }
77
78 async componentDidMount() {
79
80 // Fetch review again if block loaded after saving.
81 if ( this.props.attributes.id ) {
82 let result = await apiFetch({ path: `wp/v2/visualizer/${this.props.attributes.id}` }).catch( function( error ) {
83 });
84
85 if ( result ) {
86 this.setState({
87 chart: result['chart_data']
88 });
89 } else {
90
91 // if the chart is not found.
92 this.setState({
93 route: 'error'
94 });
95 }
96 }
97 }
98
99 async getChart( id ) {
100 await this.setState({
101 isLoading: 'getChart'
102 });
103
104 let result = await apiFetch({ path: `wp/v2/visualizer/${id}` });
105
106 this.setState({
107 route: 'chartSelect',
108 chart: result['chart_data'],
109 isLoading: true,
110 isModified: true
111 });
112
113 this.props.setAttributes({
114 id,
115 route: 'chartSelect',
116 lazy: -1
117 });
118 }
119
120 editChart() {
121 this.setState({ route: 'chartSelect' });
122 this.props.setAttributes({ route: 'chartSelect' });
123 }
124
125 editSettings( settings ) {
126 let chart = { ...this.state.chart };
127 chart['visualizer-settings'] = settings;
128 this.setState({
129 chart,
130 isModified: true
131 });
132 }
133
134 editPermissions( permissions ) {
135 let chart = { ...this.state.chart };
136 chart['visualizer-permissions'] = permissions;
137 this.setState({
138 chart,
139 isModified: true
140 });
141 }
142
143 readUploadedFile( e ) {
144 const fileTobeRead = e.current.files[0];
145 const fileReader = new FileReader();
146 fileReader.onload = () => {
147 const data = CSVToArray( fileReader.result );
148 this.editChartData( data, 'Visualizer_Source_Csv' );
149 };
150 fileReader.readAsText( fileTobeRead );
151 }
152
153 editURL( url ) {
154 let chart = { ...this.state.chart };
155 chart['visualizer-chart-url'] = url;
156 this.setState({ chart });
157 }
158
159 editSchedule( schedule ) {
160 let chart = { ...this.state.chart };
161 chart['visualizer-chart-schedule'] = schedule;
162 this.setState({
163 chart,
164 isModified: true
165 });
166 }
167
168 editJSONSchedule( schedule ) {
169 let chart = { ...this.state.chart };
170 chart['visualizer-json-schedule'] = schedule;
171 this.setState({
172 chart,
173 isModified: true
174 });
175 }
176
177 editJSONURL( url ) {
178 let chart = { ...this.state.chart };
179 chart['visualizer-json-url'] = url;
180 this.setState({ chart });
181 }
182
183 editJSONHeaders( headers ) {
184 let chart = { ...this.state.chart };
185 delete headers.username;
186 delete headers.password;
187 chart['visualizer-json-headers'] = headers;
188 this.setState({ chart });
189 }
190
191 editJSONRoot( root ) {
192 let chart = { ...this.state.chart };
193 chart['visualizer-json-root'] = root;
194 this.setState({ chart });
195 }
196
197 editJSONPaging( root ) {
198 let chart = { ...this.state.chart };
199 chart['visualizer-json-paging'] = root;
200 this.setState({ chart });
201 }
202
203 JSONImportData( name, series, data ) {
204 let chart = { ...this.state.chart };
205 chart['visualizer-source'] = name;
206 chart['visualizer-default-data'] = 0;
207 chart['visualizer-series'] = series;
208 chart['visualizer-data'] = data;
209 this.setState({
210 chart,
211 isModified: true
212 });
213 }
214
215 editDatabaseSchedule( schedule ) {
216 let chart = { ...this.state.chart };
217 chart['visualizer-db-schedule'] = schedule;
218 this.setState({
219 chart,
220 isModified: true
221 });
222 }
223
224 databaseImportData( query, name, series, data ) {
225 let chart = { ...this.state.chart };
226 chart['visualizer-source'] = name;
227 chart['visualizer-default-data'] = 0;
228 chart['visualizer-series'] = series;
229 chart['visualizer-data'] = data;
230 chart['visualizer-db-query'] = query;
231 this.setState({
232 chart,
233 isModified: true
234 });
235 }
236
237 uploadData( scheduled = false ) {
238 this.setState({
239 isLoading: 'uploadData',
240 isScheduled: scheduled
241 });
242
243 apiRequest({ path: `/visualizer/v1/upload-data?url=${this.state.chart['visualizer-chart-url']}`, method: 'POST' }).then(
244 ( data ) => {
245 if ( 2 <= Object.keys( data ).length ) {
246 let chart = { ...this.state.chart };
247
248 chart['visualizer-source'] = 'Visualizer_Source_Csv_Remote';
249 chart['visualizer-default-data'] = 0;
250 chart['visualizer-series'] = data.series;
251 chart['visualizer-data'] = data.data;
252
253 let series = chart['visualizer-series'];
254 let settings = chart['visualizer-settings'];
255 let map = series;
256 let fieldName = 'series';
257
258 if ( 'pie' === chart['visualizer-chart-type']) {
259 map = chart['visualizer-data'];
260 fieldName = 'slices';
261 }
262
263 map.map( ( i, index ) => {
264 if ( 'pie' !== chart['visualizer-chart-type'] && 0 === index ) {
265 return;
266 }
267
268 const seriesIndex = 'pie' !== chart['visualizer-chart-type'] ? index - 1 : index;
269
270 if ( settings[fieldName][seriesIndex] === undefined ) {
271 settings[fieldName][seriesIndex] = {};
272 settings[fieldName][seriesIndex].temp = 1;
273 }
274 });
275
276 settings[fieldName] = settings[fieldName].filter( ( i, index ) => {
277 const length = 'pie' !== chart['visualizer-chart-type'] ? map.length - 1 : map.length;
278 return index < length;
279 });
280
281 chart['visualizer-settings'] = settings;
282
283 this.setState({
284 chart,
285 isModified: true,
286 isLoading: false
287 });
288
289 return data;
290 }
291
292 this.setState({
293 isLoading: false
294 });
295 },
296 ( err ) => {
297 this.setState({
298 isLoading: false
299 });
300
301 return err;
302 }
303 );
304 }
305
306 async getChartData( id ) {
307 await this.setState({
308 isLoading: 'getChartData'
309 });
310
311 let result = await apiFetch({ path: `wp/v2/visualizer/${id}` });
312
313 let chart = { ...this.state.chart };
314
315 chart['visualizer-source'] = 'Visualizer_Source_Csv';
316 chart['visualizer-default-data'] = 0;
317 chart['visualizer-series'] = result['chart_data']['visualizer-series'];
318 chart['visualizer-data'] = result['chart_data']['visualizer-data'];
319
320 this.setState({
321 isLoading: false,
322 chart
323 });
324 }
325
326 editChartData( chartData, source ) {
327 let chart = { ...this.state.chart };
328 let series = [];
329 let settings = { ...chart['visualizer-settings'] };
330 let type = chart['visualizer-chart-type'];
331 chartData[0].map( ( i, index ) => {
332 series[index] = {
333 label: i,
334 type: chartData[1][index]
335 };
336 });
337
338 chartData.splice( 0, 2 );
339
340 let map = series;
341 let fieldName = 'series';
342
343 switch ( type ) {
344 case 'pie':
345 map = chartData;
346 fieldName = 'slices';
347
348 // pie charts are finicky about a number being a number
349 // and editing a number makes it a string
350 // so let's convert it back into a number.
351 chartData.map( ( i, index ) => {
352 switch ( series[1].type ) {
353 case 'number':
354 i[1] = parseFloat( i[1]);
355 break;
356 }
357 });
358 break;
359 case 'tabular':
360
361 // table charts are finicky about a boolean being a boolean
362 // and editing a boolean makes it a string
363 // so let's convert it back into a boolean.
364 chartData.map( ( i, index ) => {
365 series.map( ( seriesObject, seriesIndex ) => {
366 switch ( seriesObject.type ) {
367 case 'boolean':
368 if ( 'string' === typeof i[seriesIndex]) {
369 i[seriesIndex] = 'true' === i[seriesIndex];
370 }
371 break;
372 }
373 });
374 });
375 break;
376 }
377
378 map.map( ( i, index ) => {
379 if ( 'pie' !== type && 0 === index ) {
380 return;
381 }
382
383 const seriesIndex = 'pie' !== type ? index - 1 : index;
384
385 if ( Array.isArray( settings[fieldName]) && settings[fieldName][seriesIndex] === undefined ) {
386 settings[fieldName][seriesIndex] = {};
387 settings[fieldName][seriesIndex].temp = 1;
388 }
389 });
390
391 if ( Array.isArray( settings[fieldName]) ) {
392 settings[fieldName] = settings[fieldName].filter( ( i, index ) => {
393 const length = -1 >= [ 'pie', 'tabular', 'dataTable' ].indexOf( type ) ? map.length - 1 : map.length;
394 return index < length;
395 });
396 }
397
398 chart['visualizer-source'] = source;
399 chart['visualizer-default-data'] = 0;
400 chart['visualizer-data'] = chartData;
401 chart['visualizer-series'] = series;
402 chart['visualizer-settings'] = settings;
403 chart['visualizer-chart-url'] = '';
404
405 this.setState({
406 chart,
407 isModified: true,
408 isScheduled: false
409 });
410 }
411
412 updateChart() {
413 this.setState({ isLoading: 'updateChart' });
414
415 const data = this.state.chart;
416
417 if ( false === this.state.isScheduled ) {
418 data['visualizer-chart-schedule'] = '';
419 }
420
421 let fieldName = 'series';
422
423 if ( 'pie' === data['visualizer-chart-type']) {
424 fieldName = 'slices';
425 }
426
427 // no series for bubble and timeline charts.
428 if ( -1 >= [ 'bubble', 'timeline' ].indexOf( data['visualizer-chart-type']) ) {
429 Object.keys( data['visualizer-settings'][fieldName])
430 .map( i => {
431 if ( data['visualizer-settings'][fieldName][i] !== undefined ) {
432 if ( data['visualizer-settings'][fieldName][i].temp !== undefined ) {
433 delete data['visualizer-settings'][fieldName][i].temp;
434 }
435 }
436 }
437 );
438 }
439
440 apiRequest({ path: `/visualizer/v1/update-chart?id=${ this.props.attributes.id }`, method: 'POST', data: data }).then(
441 ( data ) => {
442
443 this.setState({
444 isLoading: false,
445 isModified: false
446 });
447
448 return data;
449 },
450 ( err ) => {
451 return err;
452 }
453 );
454 }
455
456 render() {
457 if ( 'error' === this.state.route ) {
458 return (
459 <Notice
460 status="error"
461 isDismissible={ false }
462 >
463 <Dashicon icon="chart-pie" />
464 { __( 'This chart is not available; it might have been deleted. Please delete this block and resubmit your chart.' ) }
465 </Notice>
466 );
467 }
468
469 if ( 'renderChart' === this.state.route && null !== this.state.chart ) {
470 return (
471 <ChartRender
472 id={ this.props.attributes.id }
473 chart={ this.state.chart }
474 className={ this.props.className }
475 editChart={ this.editChart }
476 />
477 );
478 }
479
480 return (
481 <div className="visualizer-settings">
482
483 <div className="visualizer-settings__title">
484
485 <Dashicon icon="chart-pie" />
486 { __( 'Visualizer' ) }
487
488 </div>
489
490 { 'home' === this.state.route && (
491 <div className="visualizer-settings__content">
492 <div className="visualizer-settings__content-description">
493 { __( 'Make a new chart or display an existing one?' ) }
494 </div>
495
496 { /* You can apply "locked" class to lock any of the following list items. */ }
497
498 <a
499 href={ visualizerLocalize.adminPage }
500 target="_blank"
501 className="visualizer-settings__content-option"
502 >
503
504 <span className="visualizer-settings__content-option-title">
505 { __( 'Create a new chart' ) }
506 </span>
507
508 <div className="visualizer-settings__content-option-icon">
509 <Dashicon icon="arrow-right-alt2" />
510 </div>
511
512 </a>
513
514 <div
515 className="visualizer-settings__content-option"
516 onClick={ () => {
517 this.setState({ route: 'showCharts' });
518 this.props.setAttributes({ route: 'showCharts' });
519 } }
520 >
521
522 <span className="visualizer-settings__content-option-title">
523 { __( 'Display an existing chart' ) }
524 </span>
525
526 <div className="visualizer-settings__content-option-icon">
527 <Dashicon icon="arrow-right-alt2" />
528 </div>
529
530 </div>
531
532 </div>
533 ) }
534
535 { ( ( 'getChart' === this.state.isLoading ) || ( 'chartSelect' === this.state.route && null === this.state.chart ) || ( 'renderChart' === this.state.route && null === this.state.chart ) ) && (
536 <Placeholder>
537 <Spinner/>
538 </Placeholder>
539 ) }
540
541 { ( 'showCharts' === this.state.route && false === this.state.isLoading ) && <Charts getChart={ this.getChart }/> }
542
543 { ( 'chartSelect' === this.state.route && null !== this.state.chart ) &&
544 <ChartSelect
545 id={ this.props.attributes.id }
546 attributes={ this.props.attributes }
547 chart={ this.state.chart }
548 editSettings={ this.editSettings }
549 editPermissions={ this.editPermissions }
550 url={ this.state.url }
551 readUploadedFile={ this.readUploadedFile }
552 editURL={ this.editURL }
553 editSchedule={ this.editSchedule }
554 editJSONURL={ this.editJSONURL }
555 editJSONHeaders={ this.editJSONHeaders }
556 editJSONSchedule={ this.editJSONSchedule }
557 editJSONRoot={ this.editJSONRoot }
558 editJSONPaging={ this.editJSONPaging }
559 JSONImportData={ this.JSONImportData }
560 editDatabaseSchedule={ this.editDatabaseSchedule }
561 databaseImportData={ this.databaseImportData }
562 uploadData={ this.uploadData }
563 getChartData={ this.getChartData }
564 editChartData={ this.editChartData }
565 isLoading={ this.state.isLoading }
566 />
567 }
568
569 <div className="visualizer-settings__controls">
570
571 { ( 'showCharts' === this.state.route || 'chartSelect' === this.state.route ) &&
572 <ButtonGroup>
573
574 <Button
575 isDefault
576 isLarge
577 onClick={ () => {
578 let route;
579 if ( 'showCharts' === this.state.route ) {
580 route = 'home';
581 } else if ( 'chartSelect' === this.state.route ) {
582 route = 'showCharts';
583 }
584 this.setState({ route });
585 this.props.setAttributes({ route });
586 } }
587 >
588 { __( 'Back' ) }
589 </Button>
590
591 { 'chartSelect' === this.state.route &&
592 <Fragment>
593
594 { false === this.state.isModified ?
595 <Button
596 isDefault
597 isLarge
598 className="visualizer-bttn-done"
599 onClick={ () => {
600 this.setState({ route: 'renderChart', isModified: true });
601 this.props.setAttributes({ route: 'renderChart' });
602 } }
603 >
604 { __( 'Done' ) }
605 </Button> :
606 <Button
607 isPrimary
608 isLarge
609 className="visualizer-bttn-save"
610 isBusy={ 'updateChart' === this.state.isLoading }
611 disabled={ 'updateChart' === this.state.isLoading }
612 onClick={ this.updateChart }
613 >
614 { __( 'Save' ) }
615 </Button>
616 }
617
618 </Fragment>
619 }
620
621 </ButtonGroup>
622 }
623
624 </div>
625 </div>
626 );
627 }
628 }
629
630 export default Editor;
631