Is there a way to set width of the panels?

Trying to set the pages up with a single panel on the left which is fixed-width, so as to always have enough space for the list of links to display there, but without taking more than needed. The “Small” option isn’t wide enough on smaller monitors; the “Medium” option takes too much on anything but small monitors. Is there someplace proper to specify a fixed width for this?

We have been requested by our users if this panel could be variable and it’s width dragged by mouse. Is this worth a feature request or way beyond possibilities?

Regards, Simpel

1 Like

Related: Loading...

The following JavaScriptExtension uses the CSS resize feature to make the width of a panel dynamic.

 var panelObserver = new ResizeObserver(function (entries) {
      entries.forEach(function (entry) {
          var leftPanelsWidth = function () {
              var leftPanels = document.getElementById("leftPanels");
              if (leftPanels == null) {
                  return 0
              } else {
                  return leftPanels.getWidth()
              }
          };
          var rightPanelsWidth = function () {
              var rightPanels = document.getElementById("rightPanels");
              if (rightPanels == null) {
                  return 0
              } else {
                  return rightPanels.getWidth()
              }
          };
          if (entry.target.id == "leftPanels" || entry.target.id == "rightPanels") {
              var contentColumn = document.getElementById("contentcolumn").children[0];
              var leftPanels = document.getElementById("leftPanels");
              var containerWidth = document.getElementById("contentcontainerinner").getWidth();
              var paddingCorrection = 60;
              contentColumn.style["left"] = 100 * leftPanelsWidth() / containerWidth + "%";
              contentColumn.style["width"] = 100 * (containerWidth - rightPanelsWidth() - leftPanelsWidth() - paddingCorrection) / containerWidth + "%";
              if (leftPanels != null) {
                  leftPanels.style["right"] = contentColumn.style["width"]
              };
          };
      });
  });

  if (document.getElementById("leftPanels") != null) {
      document.getElementById("leftPanels").style["resize"] = "horizontal";
      document.getElementById("leftPanels").style["overflow"] = "hidden";
      panelObserver.observe(document.getElementById("leftPanels"));
  };

  if (document.getElementById("rightPanels") != null) {
      document.getElementById("rightPanels").style["resize"] = "horizontal";
      document.getElementById("rightPanels").style["overflow"] = "hidden";
      panelObserver.observe(document.getElementById("rightPanels"));
  };
 

It is a bit “dirty”, as it uses the HTML ids of the page layout, but it works.

(Used with flamingo skin).

2 Likes

Since the above ticket was closed as ‘won’t fix’ we had to find another solution.

I made several attempts to find the right compromise between hackiness and user-friendliness.

This is what we have today. There are some requirements:

  1. We use the navigation panel on the left side.
  2. We don’t have any other panel on the left.
  3. We use Flamingo skin.

JavaScriptExtension:

document.addEventListener("DOMContentLoaded", function () {
  const leftPanel = document.getElementById('leftPanels');

  if (window.innerWidth > 991) {
    if (leftPanel) {
      try {
        const container = document.querySelector("#contentcontainerinner > .leftsidecolumns");
        const main = container.querySelector(".main");

        // create splitter
        const splitter = document.createElement("div");
        splitter.id = "splitter";
        splitter.title = "Click and drag to adjust the width. Double-click to reset the width.";
        splitter.style.height = main.offsetHeight + "px";

        // insert splitter
        container.insertBefore(splitter, leftPanel.nextSibling);

        // double-click splitter: delete localStorage and reload page to reset
        splitter.addEventListener("dblclick", () => {
          localStorage.removeItem("leftPanelWidthPercent");
          location.reload();
        });

        // drag functions
        let isDragging = false;

        splitter.addEventListener("mousedown", function () {
          isDragging = true;
          document.body.style.cursor = "ew-resize";
        });

        document.addEventListener("mousemove", function (e) {
          if (!isDragging) return;
          const newWidth = e.clientX - container.getBoundingClientRect().left;
          if (newWidth > 100 && newWidth < window.innerWidth * 0.8) {
            const containerWidth = container.offsetWidth;
            const percent = ((newWidth / containerWidth) * 100).toFixed(1);
            document.documentElement.style.setProperty("--variable-left-panel-width", percent + "%");
            document.documentElement.style.setProperty("--variable-main-width", 100 - percent + "%");
            localStorage.setItem("leftPanelWidthPercent", percent);
          }
        });

        document.addEventListener("mouseup", function () {
          isDragging = false;
          document.body.style.cursor = "";
        });

      } catch (err) {
        //console.log(err)
      }
    }
  }
});

UIExtension ‘org.xwiki.platform.html.head’ as extension point ID:

{{html}}
<script>
// following function is executed in <head> as it is inserted with this UIX in 'org.xwiki.platform.html.head' as extension point ID
// This code has to be executed very early otherwise the width of navigation panel and article will jump (first default and later requested values)
// see https://www.xwiki.org/xwiki/bin/view/Documentation/DevGuide/Tutorials/UIXTutorial and
// see https://www.xwiki.org/xwiki/bin/view/Documentation/DevGuide/ExtensionPoint
(function() {
  const percent = localStorage.getItem("leftPanelWidthPercent");
  if (percent) {
    document.documentElement.style.setProperty("--variable-left-panel-width", percent + "%");
    document.documentElement.style.setProperty("--variable-main-width", 100 - percent + "%");
  } else {
    document.documentElement.style.setProperty("--variable-left-panel-width", "16.7%");
    document.documentElement.style.setProperty("--variable-main-width", "83.3%");
  }
})();
</script>
{{/html}}

StyleSheetExtension:

/* only bigger devices */
@media (min-width: 992px) {
  #body.hideright.panel-left-width-Medium .main {
    left: var(--variable-left-panel-width, 16.7%);
    width: var(--variable-main-width, 83.3%);
  }
  #body.hideright.panel-left-width-Medium #leftPanels {
    width: var(--variable-left-panel-width, 16.7%);
    right: var(--variable-main-width, 83.3%);
  }
  #splitter {
    width: 11px;
    position: absolute;
    left: calc(var(--variable-left-panel-width) - 5px);
    z-index: 10;
    background: transparent;
    transition: background .2s;
    cursor: ew-resize;
  }
  #splitter::before {
    content: "";
    position: absolute;
    left: 5px;
    top: 0;
    bottom: 0;
    width: 1px;
    background: #e8e8e8;
  }
  #splitter:hover::before {
    background: #888;
  }
}

Note that since XWiki 17.3.0, panel resizing is supported by XWiki, no need for any customizations.

2 Likes

That’s great. So I remove my code when upgrading next year as we do use the lts.