TextPanel.tsx 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. // Libraries
  2. import React, { PureComponent } from 'react';
  3. import Remarkable from 'remarkable';
  4. import { debounce } from 'lodash';
  5. // Utils
  6. import { sanitize } from 'app/core/utils/text';
  7. import config from 'app/core/config';
  8. // Types
  9. import { TextOptions } from './types';
  10. import { PanelProps } from '@grafana/ui/src/types';
  11. interface Props extends PanelProps<TextOptions> {}
  12. interface State {
  13. html: string;
  14. }
  15. export class TextPanel extends PureComponent<Props, State> {
  16. remarkable: Remarkable;
  17. constructor(props) {
  18. super(props);
  19. this.state = {
  20. html: this.processContent(props.options),
  21. };
  22. }
  23. updateHTML = debounce(() => {
  24. const html = this.processContent(this.props.options);
  25. if (html !== this.state.html) {
  26. this.setState({ html });
  27. }
  28. }, 150);
  29. componentDidUpdate(prevProps: Props) {
  30. // Since any change could be referenced in a template variable,
  31. // This needs to process everytime (with debounce)
  32. this.updateHTML();
  33. }
  34. prepareHTML(html: string): string {
  35. const { replaceVariables } = this.props;
  36. html = config.disableSanitizeHtml ? html : sanitize(html);
  37. return replaceVariables(html);
  38. }
  39. prepareText(content: string): string {
  40. return this.prepareHTML(
  41. content
  42. .replace(/&/g, '&amp;')
  43. .replace(/>/g, '&gt;')
  44. .replace(/</g, '&lt;')
  45. .replace(/\n/g, '<br/>')
  46. );
  47. }
  48. prepareMarkdown(content: string): string {
  49. if (!this.remarkable) {
  50. this.remarkable = new Remarkable();
  51. }
  52. return this.prepareHTML(this.remarkable.render(content));
  53. }
  54. processContent(options: TextOptions): string {
  55. const { mode, content } = options;
  56. if (!content) {
  57. return '';
  58. }
  59. if (mode === 'markdown') {
  60. return this.prepareMarkdown(content);
  61. }
  62. if (mode === 'html') {
  63. return this.prepareHTML(content);
  64. }
  65. return this.prepareText(content);
  66. }
  67. render() {
  68. const { html } = this.state;
  69. return <div className="markdown-html panel-text-content" dangerouslySetInnerHTML={{ __html: html }} />;
  70. }
  71. }