PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.10.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.10.1
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.10.1, at classes/Visualizer/Gutenberg/src/Editor.js

646 lines 16.8 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 if ( '1' !== settings.pagination ) {
128 delete settings.pageSize;
129 }
130 chart['visualizer-settings'] = settings;
131 this.setState({
132 chart,
133 isModified: true
134 });
135 }
136
137 editPermissions( permissions ) {
138 let chart = { ...this.state.chart };
139 chart['visualizer-permissions'] = permissions;
140 this.setState({
141 chart,
142 isModified: true
143 });
144 }
145
146 readUploadedFile( e ) {
147 const fileTobeRead = e.current.files[0];
148 const fileReader = new FileReader();
149 fileReader.onload = () => {
150 const data = CSVToArray( fileReader.result );
151 this.editChartData( data, 'Visualizer_Source_Csv' );
152 };
153 fileReader.readAsText( fileTobeRead );
154 }
155
156 editURL( url ) {
157 let chart = { ...this.state.chart };
158 chart['visualizer-chart-url'] = url;
159 this.setState({ chart });
160 }
161
162 editSchedule( schedule ) {
163 let chart = { ...this.state.chart };
164 chart['visualizer-chart-schedule'] = schedule;
165 this.setState({
166 chart,
167 isModified: true
168 });
169 }
170
171 editJSONSchedule( schedule ) {
172 let chart = { ...this.state.chart };
173 chart['visualizer-json-schedule'] = schedule;
174 this.setState({
175 chart,
176 isModified: true
177 });
178 }
179
180 editJSONURL( url ) {
181 let chart = { ...this.state.chart };
182 chart['visualizer-json-url'] = url;
183 this.setState({ chart });
184 }
185
186 editJSONHeaders( headers ) {
187 let chart = { ...this.state.chart };
188 delete headers.username;
189 delete headers.password;
190 chart['visualizer-json-headers'] = headers;
191 this.setState({ chart });
192 }
193
194 editJSONRoot( root ) {
195 let chart = { ...this.state.chart };
196 chart['visualizer-json-root'] = root;
197 this.setState({ chart });
198 }
199
200 editJSONPaging( root ) {
201 let chart = { ...this.state.chart };
202 chart['visualizer-json-paging'] = root;
203 this.setState({ chart });
204 }
205
206 JSONImportData( name, series, data ) {
207 let chart = { ...this.state.chart };
208 chart['visualizer-source'] = name;
209 chart['visualizer-default-data'] = 0;
210 chart['visualizer-series'] = series;
211 chart['visualizer-data'] = data;
212 this.setState({
213 chart,
214 isModified: true
215 });
216 }
217
218 editDatabaseSchedule( schedule ) {
219 let chart = { ...this.state.chart };
220 chart['visualizer-db-schedule'] = schedule;
221 this.setState({
222 chart,
223 isModified: true
224 });
225 }
226
227 databaseImportData( query, name, series, data ) {
228 let chart = { ...this.state.chart };
229 chart['visualizer-source'] = name;
230 chart['visualizer-default-data'] = 0;
231 chart['visualizer-series'] = series;
232 chart['visualizer-data'] = data;
233 chart['visualizer-db-query'] = query;
234 this.setState({
235 chart,
236 isModified: true
237 });
238 }
239
240 uploadData( scheduled = false ) {
241 this.setState({
242 isLoading: 'uploadData',
243 isScheduled: scheduled
244 });
245
246 apiRequest({ path: `/visualizer/v1/upload-data?url=${this.state.chart['visualizer-chart-url']}`, method: 'POST' }).then(
247 ( data ) => {
248 if ( 2 <= Object.keys( data ).length ) {
249 let chart = { ...this.state.chart };
250
251 chart['visualizer-source'] = 'Visualizer_Source_Csv_Remote';
252 chart['visualizer-default-data'] = 0;
253 chart['visualizer-series'] = data.series;
254 chart['visualizer-data'] = data.data;
255
256 let series = chart['visualizer-series'];
257 let settings = chart['visualizer-settings'];
258 let map = series;
259 let fieldName = 'series';
260
261 if ( 'pie' === chart['visualizer-chart-type']) {
262 map = chart['visualizer-data'];
263 fieldName = 'slices';
264 }
265
266 map.map( ( i, index ) => {
267 if ( 'pie' !== chart['visualizer-chart-type'] && 0 === index ) {
268 return;
269 }
270
271 const seriesIndex = 'pie' !== chart['visualizer-chart-type'] ? index - 1 : index;
272
273 if ( settings[fieldName][seriesIndex] === undefined ) {
274 settings[fieldName][seriesIndex] = {};
275 settings[fieldName][seriesIndex].temp = 1;
276 }
277 });
278
279 settings[fieldName] = settings[fieldName].filter( ( i, index ) => {
280 const length = 'pie' !== chart['visualizer-chart-type'] ? map.length - 1 : map.length;
281 return index < length;
282 });
283
284 chart['visualizer-settings'] = settings;
285
286 this.setState({
287 chart,
288 isModified: true,
289 isLoading: false
290 });
291
292 return data;
293 }
294
295 this.setState({
296 isLoading: false
297 });
298 },
299 ( err ) => {
300 this.setState({
301 isLoading: false
302 });
303
304 return err;
305 }
306 );
307 }
308
309 async getChartData( id ) {
310 await this.setState({
311 isLoading: 'getChartData'
312 });
313
314 let result = await apiFetch({ path: `wp/v2/visualizer/${id}` });
315
316 let chart = { ...this.state.chart };
317
318 chart['visualizer-source'] = 'Visualizer_Source_Csv';
319 chart['visualizer-default-data'] = 0;
320 chart['visualizer-series'] = result['chart_data']['visualizer-series'];
321 chart['visualizer-data'] = result['chart_data']['visualizer-data'];
322
323 this.setState({
324 isLoading: false,
325 chart
326 });
327 }
328
329 editChartData( chartData, source ) {
330 let chart = { ...this.state.chart };
331 let series = [];
332 let settings = { ...chart['visualizer-settings'] };
333 let type = chart['visualizer-chart-type'];
334 chartData[0].map( ( i, index ) => {
335 series[index] = {
336 label: i,
337 type: chartData[1][index]
338 };
339 });
340
341 chartData.splice( 0, 2 );
342
343 let map = series;
344 let fieldName = 'series';
345
346 switch ( type ) {
347 case 'pie':
348 map = chartData;
349 fieldName = 'slices';
350
351 // pie charts are finicky about a number being a number
352 // and editing a number makes it a string
353 // so let's convert it back into a number.
354 chartData.map( ( i, index ) => {
355 switch ( series[1].type ) {
356 case 'number':
357 i[1] = parseFloat( i[1]);
358 break;
359 }
360 });
361 break;
362 case 'tabular':
363
364 // table charts are finicky about a boolean being a boolean
365 // and editing a boolean makes it a string
366 // so let's convert it back into a boolean.
367 chartData.map( ( i, index ) => {
368 series.map( ( seriesObject, seriesIndex ) => {
369 switch ( seriesObject.type ) {
370 case 'boolean':
371 if ( 'string' === typeof i[seriesIndex]) {
372 i[seriesIndex] = 'true' === i[seriesIndex];
373 }
374 break;
375 }
376 });
377 });
378 break;
379 }
380
381 map.map( ( i, index ) => {
382 if ( 'pie' !== type && 0 === index ) {
383 return;
384 }
385
386 const seriesIndex = 'pie' !== type ? index - 1 : index;
387
388 if ( Array.isArray( settings[fieldName]) && settings[fieldName][seriesIndex] === undefined ) {
389 settings[fieldName][seriesIndex] = {};
390 settings[fieldName][seriesIndex].temp = 1;
391 }
392 });
393
394 if ( Array.isArray( settings[fieldName]) ) {
395 settings[fieldName] = settings[fieldName].filter( ( i, index ) => {
396 const length = -1 >= [ 'pie', 'tabular', 'dataTable' ].indexOf( type ) ? map.length - 1 : map.length;
397 return index < length;
398 });
399 }
400
401 chart['visualizer-source'] = source;
402 chart['visualizer-default-data'] = 0;
403 chart['visualizer-data'] = chartData;
404 chart['visualizer-series'] = series;
405 chart['visualizer-settings'] = settings;
406 chart['visualizer-chart-url'] = '';
407
408 this.setState({
409 chart,
410 isModified: true,
411 isScheduled: false
412 });
413 }
414
415 updateChart() {
416 this.setState({ isLoading: 'updateChart' });
417
418 const data = this.state.chart;
419
420 if ( false === this.state.isScheduled ) {
421 data['visualizer-chart-schedule'] = '';
422 }
423
424 let fieldName = 'series';
425
426 if ( 'pie' === data['visualizer-chart-type']) {
427 fieldName = 'slices';
428 }
429
430 // no series for bubble and timeline charts.
431 if ( -1 >= [ 'bubble', 'timeline' ].indexOf( data['visualizer-chart-type']) ) {
432 Object.keys( data['visualizer-settings'][fieldName])
433 .map( i => {
434 if ( data['visualizer-settings'][fieldName][i] !== undefined ) {
435 if ( data['visualizer-settings'][fieldName][i].temp !== undefined ) {
436 delete data['visualizer-settings'][fieldName][i].temp;
437 }
438 }
439 }
440 );
441 }
442
443 apiRequest({ path: `/visualizer/v1/update-chart?id=${ this.props.attributes.id }`, method: 'POST', data: data }).then(
444 ( data ) => {
445
446 this.setState({
447 isLoading: false,
448 isModified: false
449 });
450
451 return data;
452 },
453 ( err ) => {
454 return err;
455 }
456 );
457 }
458
459 render() {
460 if ( 'error' === this.state.route ) {
461 return (
462 <Notice
463 status="error"
464 isDismissible={ false }
465 >
466 <Dashicon icon="chart-pie" />
467 { __( 'This chart is not available; it might have been deleted. Please delete this block and resubmit your chart.' ) }
468 </Notice>
469 );
470 }
471
472 if ( '1' === visualizerLocalize.isFullSiteEditor ) {
473 return (
474 <Notice
475 status="error"
476 isDismissible={ false }
477 >
478 <Dashicon icon="chart-pie" />
479 { __( 'Visualizer block charts are currently not available for selection here, you must visit the library, get the shortcode, and add the chart here in a shortcode tag.' ) }
480 </Notice>
481 );
482 }
483
484 if ( 'renderChart' === this.state.route && null !== this.state.chart ) {
485 return (
486 <ChartRender
487 id={ this.props.attributes.id }
488 chart={ this.state.chart }
489 className={ this.props.className }
490 editChart={ this.editChart }
491 />
492 );
493 }
494
495 return (
496 <div className="visualizer-settings">
497
498 <div className="visualizer-settings__title">
499
500 <Dashicon icon="chart-pie" />
501 { __( 'Visualizer' ) }
502
503 </div>
504
505 { 'home' === this.state.route && (
506 <div className="visualizer-settings__content">
507 <div className="visualizer-settings__content-description">
508 { __( 'Make a new chart or display an existing one?' ) }
509 </div>
510
511 { /* You can apply "locked" class to lock any of the following list items. */ }
512
513 <a
514 href={ visualizerLocalize.adminPage }
515 target="_blank"
516 className="visualizer-settings__content-option"
517 >
518
519 <span className="visualizer-settings__content-option-title">
520 { __( 'Create a new chart' ) }
521 </span>
522
523 <div className="visualizer-settings__content-option-icon">
524 <Dashicon icon="arrow-right-alt2" />
525 </div>
526
527 </a>
528
529 <div
530 className="visualizer-settings__content-option"
531 onClick={ () => {
532 this.setState({ route: 'showCharts' });
533 this.props.setAttributes({ route: 'showCharts' });
534 } }
535 >
536
537 <span className="visualizer-settings__content-option-title">
538 { __( 'Display an existing chart' ) }
539 </span>
540
541 <div className="visualizer-settings__content-option-icon">
542 <Dashicon icon="arrow-right-alt2" />
543 </div>
544
545 </div>
546
547 </div>
548 ) }
549
550 { ( ( 'getChart' === this.state.isLoading ) || ( 'chartSelect' === this.state.route && null === this.state.chart ) || ( 'renderChart' === this.state.route && null === this.state.chart ) ) && (
551 <Placeholder>
552 <Spinner/>
553 </Placeholder>
554 ) }
555
556 { ( 'showCharts' === this.state.route && false === this.state.isLoading ) && <Charts getChart={ this.getChart }/> }
557
558 { ( 'chartSelect' === this.state.route && null !== this.state.chart ) &&
559 <ChartSelect
560 id={ this.props.attributes.id }
561 attributes={ this.props.attributes }
562 chart={ this.state.chart }
563 editSettings={ this.editSettings }
564 editPermissions={ this.editPermissions }
565 url={ this.state.url }
566 readUploadedFile={ this.readUploadedFile }
567 editURL={ this.editURL }
568 editSchedule={ this.editSchedule }
569 editJSONURL={ this.editJSONURL }
570 editJSONHeaders={ this.editJSONHeaders }
571 editJSONSchedule={ this.editJSONSchedule }
572 editJSONRoot={ this.editJSONRoot }
573 editJSONPaging={ this.editJSONPaging }
574 JSONImportData={ this.JSONImportData }
575 editDatabaseSchedule={ this.editDatabaseSchedule }
576 databaseImportData={ this.databaseImportData }
577 uploadData={ this.uploadData }
578 getChartData={ this.getChartData }
579 editChartData={ this.editChartData }
580 isLoading={ this.state.isLoading }
581 />
582 }
583
584 <div className="visualizer-settings__controls">
585
586 { ( 'showCharts' === this.state.route || 'chartSelect' === this.state.route ) &&
587 <ButtonGroup>
588
589 <Button
590 isDefault
591 isLarge
592 onClick={ () => {
593 let route;
594 if ( 'showCharts' === this.state.route ) {
595 route = 'home';
596 } else if ( 'chartSelect' === this.state.route ) {
597 route = 'showCharts';
598 }
599 this.setState({ route, isLoading: false });
600 this.props.setAttributes({ route });
601 } }
602 >
603 { __( 'Back' ) }
604 </Button>
605
606 { 'chartSelect' === this.state.route &&
607 <Fragment>
608
609 { false === this.state.isModified ?
610 <Button
611 isDefault
612 isLarge
613 className="visualizer-bttn-done"
614 onClick={ () => {
615 this.setState({ route: 'renderChart', isModified: true });
616 this.props.setAttributes({ route: 'renderChart' });
617 } }
618 >
619 { __( 'Done' ) }
620 </Button> :
621 <Button
622 isPrimary
623 isLarge
624 className="visualizer-bttn-save"
625 isBusy={ 'updateChart' === this.state.isLoading }
626 disabled={ 'updateChart' === this.state.isLoading }
627 onClick={ this.updateChart }
628 >
629 { __( 'Save' ) }
630 </Button>
631 }
632
633 </Fragment>
634 }
635
636 </ButtonGroup>
637 }
638
639 </div>
640 </div>
641 );
642 }
643 }
644
645 export default Editor;
646