This issue is a meta issue for #1588158: admin menu showing at bottom and #1719440: Don't add "contextual links" to body element.

Problem: Skinr adds the contextual link class to the body element, region wrapper elements (e.g. div.region-page-bottom) even when I have made no skins available to HTML or region theme hooks. This means that Skinr modifies the behavior of CSS layouts and Javascript behaviors.

Symptoms I have encountered:
-Admin menu showing at bottom of page
-All Links impossible to click, text impossible to select. This is due to a region behaving in such a way that it spans the entire viewport because of the addition of the contextual links class.
-The entire contents of a page being copied at the bottom of the page (probably because of contextual-links javascript)
-Links impossible to click inside certain portions of a webpage because of unwanted position:relative being set on region wrapper elements that are supposed floated or absolutely positioned
-On some pageloads (usually after saving a form) the region-page-bottomgets a wrapper div with a contextual class. This region is typically used by modules that want to absolutely position something in the body and this is made impossible by the contextual link class. This will break modules like admin_menu, lightbox, colorbox, environment_indicator etc.

I would have given this normal priority if there was an easy way to prevent the behavior on certain regions but as skinr indiscriminately adds the contextual links class to the problematic elements -even if no skins are available- it is a major issue.

Also, while skinr adds the contextual_links class to these problematic elements I never see a cogwheel appear in the corner of these elements. Even when I make my skins available to the html and region theme hooks. Maybe the contextual links module does not support it?

Proposed solution: Make skinr_ui_preprocess load the contextual links class only on elements that have active skins available to the theme_hooks that correspond to the elements. Maybe some filtering can be done on $array_elements = skinr_invoke_all('skinr_elements', $variables, $original_hook, 'contextual_links'); or maybe the function needs to be re-written, I'm not sure.

Comments

jurriaanroelofs’s picture

Issue summary: View changes

[][]

moonray’s picture

Also, while skinr adds the contextual_links class to these problematic elements I never see a cogwheel appear in the corner of these elements. Even when I make my skins available to the html and region theme hooks. Maybe the contextual links module does not support it?

This is most likely due to the missing $title_prefix and $title_suffix variables in the region template. Drupal thinks it's going to have contextual links (so outputs the contextual_links class), but then can't add the actual contextual links.

jurriaanroelofs’s picture

So perhaps we should change the skinr_ui_contextual_links or skinr_ui_preprocess function to only add the contextual class to blocks and nodes?

moonray’s picture

Skinr UI doesn't actually add the classes, drupal core does, as soon as it detect a contextual link.
But we can definitely test for the availability of skins that apply to body or regions (from memory, I believe that includes: * (or all), html, region-*)

Perhaps, instead we should try fix the CSS that makes the contextual_links class misbehave? Or would that be too drastic?

jurriaanroelofs’s picture

No we don't really want to mess with all the CSS. The problem is that the contextual links class changes the position property of the element. Themes will declare position static/relative/absolute/fixed for various reasons and the contextual class just forces it to be position:relative, thus changing the way the layout behaves.
We can't fix that because we don't know with which of the for possible values for the position property is the correct one for a specific HTML.

We should just avoid putting the class on regions and the body element by default, and add it only if a region/body skin is enabled.

jurriaanroelofs’s picture

But we can definitely test for the availability of skins

How can I do this?

moonray’s picture

skinr_ui_preprocess() is where the contextual links get added (there are some exception for views and panels, if I remember correctly).
skinr_get_skin_info() will return an array with available skin plugins.

If you want to test whether or not a skin plugin is enabled on the site:

<?php
  // Apply overridden status to skins.
  $skin_infos = skinr_get_skin_info();
  foreach ($skin_infos as $skin_name => $skin_info) {
    $skin_infos[$skin_name]['status'] = skinr_skin_info_status_get($skin_infos[$skin_name]);
  }
?>

The 'theme hooks' property of a skin plugin determines whether or not a skin is allowed to be used for a particular theme.

_skinr_is_featured() might be useful (or it might not).

jurriaanroelofs’s picture

Status: Active » Needs review
StatusFileSize
new2.28 KB

This patch only adds contextual links if skins are available that apply to the current $hook and are active for the current $theme.

Status: Needs review » Needs work

The last submitted patch, contextual_only_on_active_hooks-1753486-7.patch, failed testing.

moonray’s picture

Some suggestions:

if (is_array($skin_infos[$skin_name]['theme hooks']) && isset($skin_infos[$skin_name]['status'][$theme]) && $skin_infos[$skin_name]['status'][$theme]) { can be replaced with a simple (and much faster) if (is_array(!empty($skin_infos[$skin_name]['status'][$theme])) {. is_array() is a very slow function, and empty fails without throwing an error if $skin_infos is not an array.

Add some caching to your new function; it'll be called many times, once for each theme hook. It looks like you were planning to do it, but forgot.

Instead of $skinnable_hooks[] = $active_hook; try $skinnable_hooks[$active_hook] = $active_hook;. You can then use if (isset($skinnable_hooks[$hook])) { instead of if (!in_array($hook, $skinnable_hooks)) { in skinr_ui_preprocess(), which should be much faster.

Also, why did you remove the previously added 'fix' for the HTML element? If a skin is available for it, that problem still exists... or is it not a good one?

jurriaanroelofs’s picture

I removed caching because it seemed like it would return cached results if $theme is different, like when you go to the admin theme or when some module changes the theme.

The css fix got removed by accident.

moonray’s picture

The caching should cache the settings per theme, then you can check which theme is current and pull cached settings for just that theme.
Another note: we shouldn't use the global $theme variable. Use skinr_current_theme() instead. If there's an issue with using that function, that means there's a bug and it should be fixed, instead of circumventing it here.

<?php
function skinr_get_skinnable_hooks() {
$skinnable_hooks = &drupal_static(__FUNCTION__, array());

$theme = skinr_current_theme();
if (!isset($skinnable_hooks[$theme])) {
// ...
?>
jurriaanroelofs’s picture

Here it is with your suggested improvements and static cache. I didn't add the database cache because I want to respect that certain themes support more skins then others. I guess we would have to cache per theme to have even better performance.

jurriaanroelofs’s picture

moonray’s picture

I'm seeing static cache, but no per-theme caching. Also, it's still using in_array().

jurriaanroelofs’s picture

New patch with db cache and no more in_array searches.
It's now using the current_theme function but this function doesn't work if you want to use skinr in the admin theme, like I do with this module. If I can find the time I will create an issue and/or fix for that, but if you know how to fix that feel free to cut me to it.

moonray’s picture

StatusFileSize
new2.69 KB

This patch will probably fail test (they would have to be updated; also a test specific to skinable hooks functionality would have to be added).
I fixed it up to work properly.

The question is, is this really effective considering most skins will have theme hooks set to '*', which applies to any hook?

Also, this really doesn't solve the ticket's issue, just makes it not show up under some very specific circumstances.

jurriaanroelofs’s picture

Any skinr package maintainer who has their hooks set to * should reconsider if this really applies to their skins because it doesn't make sense for most skins to be on the body tag or on a region, and that's not even taking into consideration the side-effects of putting contextual links on these elements (which doens't work anyways).

In the light of the side effects described in this issue the * selector would be appropriate in a very small number of edge cases.
Personally, I maintain about 20 skins packages for various themes and modules and I have never used the * selector, I also rarely see other themes/modules use it. Maybe we should caution against using it in the Docs or remove it alltogether, or reconsider which hooks should be skinnable and whether there should be exceptions (like the page-bottom region).

I think we should commit this patch, put in in a beta release so that people can be alleviated from the problems that are being reported (it does fix the problems for all my Drupal websites and products) and then see if we still get people reporting problems related to this issue and if necessary we can take more steps.

jurriaanroelofs’s picture

Status: Needs work » Needs review

Can I put our patch in the dev branch and ask for feedback from the community. Probably people will have skins enabled with the * selector so we will have to communicate about this when we get negative feedback.

I know this isn't a perfect solution but it works, and I don't know how to say this in english but 'Als het niet kan zoals het moet, dan moet het maar zoals het kan'

Status: Needs review » Needs work

The last submitted patch, patch_commit_2591bd5ed05c.patch, failed testing.

moonray’s picture

We need working tests, then we can commit the patch.

rooby’s picture

Even though you already know, I can confirm that the patch in #16 fixes my having contextual links everywhere displaying all the time.

rooby’s picture

Although a side effect seems to be that I now have no skinr contextual links anywhere ever. Even when something has a skin.
Makes it a bit hard to administer.

[Edit] This is because in my skin definition I had:

    'theme hooks' => array('node__my_type'),

But for contextual links to show I have to have:

    'theme hooks' => array('node', 'node__my_type'),

But I don't actually want this skin to be available on all node types so adding 'node' to theme hooks is not a good solution for me.

moonray’s picture

As rooby mentioned, besides the test, this patch needs some work. As it stands right now it only works with base theme hooks (like node, or block), not with derivates (like node__page or block__system).

moonray’s picture

Status: Needs work » Fixed
StatusFileSize
new10.68 KB

I added tests and fixed the problems with that patch. New patch attached.
Also, committed.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

sol