PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.4
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.4
4.0.8 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 All 149 releases
visualizer / classes / Visualizer / Gutenberg / src / Editor.js

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

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