Useful CSS Stuff

Adding this to the adv. stylesheet will allow popups to be resized dynamically. Without this, the size gets stuck when you're trying to reduce the size (I believe). Taken from here.

.ia_popup[id^="popup-"]{
    height: auto !important;
    max-height: 95vh; /* caps the height to 95% of the view height */
}

Also, setting the popup View's props.defaultSize.height: auto will auto-size the popup's height dynamically to its content which is quite useful.

Important note: This stops working if the popup is moved by the user, as the size is then fixed and applied directly to the popup’s DOM by IA :confused: Not sure if there’s a way around this without JS

JS fix via HTML injection… This will remove the fixed static width and heights applied by IA when the user clicks on the popup’s titlebar to drag it – experimental at best

Add this into a new file body_bottom.txt created under:

<Ignition install dir>/data/modules/com.inductiveautomation.perspective/injectables (note: in v8.3 you’ll need to create most of this folderpath manually)

<script>
  function removeInlineDimensionsAndObserve(elements) {
    elements.forEach(el => {
      // Skip if already being observed (check for a custom property)
      if (el._dimensionObserverAttached) return;
      el._dimensionObserverAttached = true;

      // Remove initial inline styles
      el.style.removeProperty('height');
      el.style.removeProperty('width');

      // Create a MutationObserver to watch for future style changes
      const observer = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
          if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
            if (el.style.height) {
              el.style.removeProperty('height');
              console.log(`Removed inline height from ${el.tagName} with classes ${el.className}`);
            }
            if (el.style.width) {
              el.style.removeProperty('width');
              console.log(`Removed inline width from ${el.tagName} with classes ${el.className}`);
            }
          }
        });
      });

      observer.observe(el, { attributes: true, attributeFilter: ['style'] });
    });
  }

  function initObserver() {
    // Initial observation of existing elements
    const initialElements = document.querySelectorAll('.popup.ia_popup');
    removeInlineDimensionsAndObserve(initialElements);

    // Watch for new elements being added to the DOM
    const domObserver = new MutationObserver(mutations => {
      mutations.forEach(mutation => {
        mutation.addedNodes.forEach(node => {
          // Check if the added node is an element
          if (node.nodeType === 1) {
            // Check if the node itself matches
            if (node.matches && node.matches('.popup.ia_popup')) {
              removeInlineDimensionsAndObserve([node]);
            }
            // Check for matching descendants
            const descendants = node.querySelectorAll ? node.querySelectorAll('.popup.ia_popup') : [];
            if (descendants.length > 0) {
              removeInlineDimensionsAndObserve(descendants);
            }
          }
        });
      });
    });

    // Start observing the entire document for added nodes
    domObserver.observe(document.body, {
      childList: true,
      subtree: true
    });

    console.log(`Started observing DOM for .popup.ia_popup elements. Initial count: ${initialElements.length}`);
  }

  // Wait for DOM to be ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initObserver);
  } else {
    // DOM is already ready
    initObserver();
  }
</script>

23 Likes