1

When using the Panels module within Drupal, I often end up with multiple gear icons stacked on top of each other, inaccessible to the Drupal admin.

For example, take a Panels page with this structure:

  1. MyCustomContentPaneTop
  2. A Drupal View
  3. MyCustomContentPaneBottom

When logged in as a Drupal admin, I can access the gear icon for MyCustomContentPaneBottom easily.

However, when I try to edit MyCustomContentPaneTop, I can only see an "Edit Panel" gear icon. I can see that this originates with this code, toward the bottom of the page.

<div class="contextual-links-wrapper contextual-links-processed">
  <a class="contextual-links-trigger" href="#">Configure</a>
  <ul class="contextual-links" style="display: none;">
    <li class="0 first last">
      <a class="colorboxNodeContextual-processed" href="/admin/structure/pages/nojs/operation/page-MyPanelPageName/handlers/page_MyPanelPageName_panel_context_2/content">Edit Panel</a>
    </li>
  </ul>
</div>

I can see in the HTML source that the gear icon does exist for MyCustomContentPaneTop, but it must be sitting in a z-index below the Panels gear icon.

<div class="pane-content">
  <div class="contextual-links-region"><div class="panel-display panel-1col clearfix" >
  <div class="panel-panel panel-col">
  <div><div class="contextual-links-region panel-pane pane-custom pane-1" >
  <div class="contextual-links-wrapper"><ul class="contextual-links"><li class="0 first last"><a href="/admin/structure/ctools-content/list/MyCustomContentPaneTop/edit">Configure content pane</a></li></ul></div>
  ...
</div> 

I know I can hack around with very specific CSS rules that apply only to pages where I discover this issue. However, is there an easy Drupal (or CSS) method to say, "If two gear icons are stacked on top of one another, stagger them by 5 pixels?"

  • Although I've wondered whether this is possible before and I find this a very interesting question, I think it's not really on-topic on this forum. I'd post this as an issue on the Panels' issue queue on drupal.org. – Jeroen Jun 10 '14 at 10:05
  • Fair point. I was looking for more of a quick hack than a "Solution for All Panels Users," so that's why I gravitated to StackExchange. The suggested answer from my co-worker might be solid enough for inclusion in the Panels module. I will follow up. – jtherkel Jun 10 '14 at 19:25
  • You should be able to do this with JS. I think it's impossible to build a reliable method for selecting overlapping gear icons in CSS or PHP. That said I do agree with @Jeroen that this belongs in the Panels issue queue, even if you're only looking for a quick hack (which may evolve into a proper patch and a commit). – marcvangend Jul 21 '14 at 7:07
  • 1
    Belongs in the module's issue queue. – marcvangend Jul 21 '14 at 7:07
2

Here's the minified version of that same Javascript, from said coworker. :)

jQuery(function($){l=[];t=[];$('.contextual-links-wrapper').each(function(){h=$(this);o=h.offset();k=o.left;v=o.top;if($.inArray(k,l)>-1&&$.inArray(v,t)>-1){h.offset({top:v+=50})}l.push(k);t.push(v)})});
  • Hey, this is terrific. I've taken y'all's work into a new Panels issue queue: drupal.org/node/2629246. Could this be a theme issue? – texas-bronius Dec 4 '15 at 23:07
  • There are potential problems with separating the left and top offsets into their own arrays. For example, if you have four gear icons where two have the same left offset and two have the same top offset, it will move two of the icons, even though it is unnecessary. I like the idea, though, so I created my own version: $(function(){var t=[];$.each($(".contextual-links-wrapper").get().reverse(),function(){var e=$(this),f=e.offset().left,o=e.offset().top;$.each(t,function(t,n){f===n.left&&o===n.top&&(o+=30,e.offset({top:o}))}),t.push({left:f,top:o})})}); – Thomas Higginbotham Jan 7 '16 at 15:25
1

A co-worker suggested the following. Use JavaScript to find the X and Y coordinates of each gear icon, and then move the icons by 50 pixels if they overlap.

I like it!

jQuery(function($) {
  // Declare Arrays
  left_array = new Array();
  top_array = new Array();

  // Get all the contexual link containers and iterate through them
  $('.contextual-links-wrapper').each(function(index){
    var this_left = $(this).offset().left;  // Set a convenience variable for the x-coord of the gear
    var this_top = $(this).offset().top;    // Set a convenience variable for the y-coord of the gear

    // If a previous link container had identical x&y coords, add 50 pixels to the current container y-coord
    if($.inArray(this_left,left_array) > -1 && $.inArray(this_top,top_array) > -1) { 
      this_top += 50;
      $(this).offset({top: this_top});
    }      

    left_array.push(this_left);  // Add the current container x-coord to the list of containers
    top_array.push(this_top);    // Add the current container y-coord to the list of containers
  });
});

Not the answer you're looking for? Browse other questions tagged or ask your own question.