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

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