utils.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. export function createValueSpan() {
  2. const span = document.createElement( 'span' );
  3. span.className = 'value';
  4. return span;
  5. }
  6. export function setText( element, text ) {
  7. if ( element && element.textContent !== text ) {
  8. element.textContent = text;
  9. }
  10. }
  11. export function getText( element ) {
  12. return element ? element.textContent : null;
  13. }
  14. export function splitPath( fullPath ) {
  15. const lastSlash = fullPath.lastIndexOf( '/' );
  16. if ( lastSlash === - 1 ) {
  17. return {
  18. path: '',
  19. name: fullPath.trim()
  20. };
  21. }
  22. const path = fullPath.substring( 0, lastSlash ).trim();
  23. const name = fullPath.substring( lastSlash + 1 ).trim();
  24. return { path, name };
  25. }
  26. export function splitCamelCase( str ) {
  27. return str.replace( /([a-z0-9])([A-Z])/g, '$1 $2' ).trim();
  28. }
  29. export function formatBytes( bytes, decimals = 2 ) {
  30. if ( bytes === 0 ) return '0 Bytes';
  31. const k = 1024;
  32. const dm = decimals < 0 ? 0 : decimals;
  33. const sizes = [ 'Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ];
  34. const i = Math.floor( Math.log( bytes ) / Math.log( k ) );
  35. return parseFloat( ( bytes / Math.pow( k, i ) ).toFixed( dm ) ) + ' ' + sizes[ i ];
  36. }
  37. export function info( parentNode, text ) {
  38. let infoIcon = parentNode.querySelector( '.info-icon' );
  39. if ( ! infoIcon ) {
  40. infoIcon = document.createElement( 'span' );
  41. infoIcon.className = 'info-icon';
  42. infoIcon.textContent = 'i';
  43. parentNode.appendChild( infoIcon );
  44. } else {
  45. const newInfoIcon = infoIcon.cloneNode( true );
  46. infoIcon.replaceWith( newInfoIcon );
  47. infoIcon = newInfoIcon;
  48. }
  49. const showTooltip = () => {
  50. const container = infoIcon.closest( '.three-inspector' ) || document.body;
  51. let tooltip = container.querySelector( '.three-inspector-info-tooltip' );
  52. if ( ! tooltip ) {
  53. tooltip = document.createElement( 'div' );
  54. tooltip.className = 'info-tooltip three-inspector-info-tooltip';
  55. container.appendChild( tooltip );
  56. }
  57. const html = text.trim().replace( /### (.*?)(?:\r?\n|$)/g, '<h3>$1</h3>' )
  58. .replace( /\*\*(.*?)\*\*/g, '<strong>$1</strong>' )
  59. .replace( /\n/g, '<br/>' );
  60. tooltip.innerHTML = html;
  61. const rect = infoIcon.getBoundingClientRect();
  62. const tooltipWidth = tooltip.getBoundingClientRect().width;
  63. // keep the centered tooltip within the viewport so it isn't clipped near an edge
  64. const margin = 8;
  65. const half = tooltipWidth / 2;
  66. const center = Math.max( margin + half, Math.min( window.innerWidth - margin - half, rect.left + rect.width / 2 ) );
  67. tooltip.style.left = center + 'px';
  68. tooltip.style.top = ( rect.top - 8 ) + 'px';
  69. tooltip.style.opacity = '1';
  70. tooltip.style.visibility = 'visible';
  71. };
  72. const hideTooltip = () => {
  73. const container = infoIcon.closest( '.three-inspector' ) || document.body;
  74. const tooltip = container.querySelector( '.three-inspector-info-tooltip' );
  75. if ( tooltip ) {
  76. tooltip.style.opacity = '0';
  77. tooltip.style.visibility = 'hidden';
  78. }
  79. };
  80. let isClickedOpen = false;
  81. const onDocumentPointerDown = ( e ) => {
  82. if ( ! infoIcon.contains( e.target ) ) {
  83. isClickedOpen = false;
  84. infoIcon.classList.remove( 'active' );
  85. hideTooltip();
  86. document.removeEventListener( 'pointerdown', onDocumentPointerDown );
  87. }
  88. };
  89. infoIcon.addEventListener( 'pointerenter', () => {
  90. showTooltip();
  91. } );
  92. infoIcon.addEventListener( 'pointerleave', () => {
  93. if ( ! isClickedOpen ) {
  94. hideTooltip();
  95. }
  96. } );
  97. infoIcon.addEventListener( 'click', ( e ) => {
  98. e.stopPropagation();
  99. isClickedOpen = ! isClickedOpen;
  100. if ( isClickedOpen ) {
  101. infoIcon.classList.add( 'active' );
  102. showTooltip();
  103. document.addEventListener( 'pointerdown', onDocumentPointerDown );
  104. } else {
  105. infoIcon.classList.remove( 'active' );
  106. hideTooltip();
  107. document.removeEventListener( 'pointerdown', onDocumentPointerDown );
  108. }
  109. } );
  110. return infoIcon;
  111. }
粤ICP备19079148号