CVS edit link for JaapB

Dear reader,

Here at the Dutch company Madcap.nl I have been developing a (drupal6-)module that works like a right-mouse-button on most operating systems. It is completely hookable by other modules and is therefor extremely versatile in it's functions.

Here we use it to move blocks around to different locations on the actual pages of the site itself (when logged in with the right access rule). It makes the blocks-admin-page obsolete because you can throw the blocks around on each page of your site. We also provide "hide on this page" and direct links for editing the block.
We also created a lot of functionality in these "contextual tips" for nodes, views, and users.

This means that each "entity" (page,node,block,view,user, etc) has a little icon in the top left corner when you mouse over them. When you click on it the contextual tip appears with all kinds of links and functions. These links and functions are hookable and thus extendable.

The module is called "contextual" and already used on some production sites. We would love to make this an open source module so everyone can enjoy it as we do.

Comments

JaapB’s picture

Status: Postponed (maintainer needs more info) » Needs review
StatusFileSize
new183.12 KB

Hereby the latest version of the contextual module for Drupal 6.

avpaderno’s picture

Issue tags: +Module review

Hello, and thanks for applying for a CVS account. I am adding the review tags, and some volunteers will review your code, pointing out what needs to be changed.

sun’s picture

Status: Needs review » Needs work

The only acceptable module and code under the project name/namespace "contextual" would be a backport of the Contextual module shipped with D7.

JaapB’s picture

Status: Needs work » Needs review
StatusFileSize
new56.63 KB

I have renamed the module to "Administer tool tip".

Attached the new version of the Administer tool tip module.
(Which also contains drag and drop for blocks as a nice extra feature.)

JaapB’s picture

StatusFileSize
new223.03 KB

I'll keep posting updates on the module while I'll wait for comments, suggestions, and maybe, just maybe, a module-page on drupal.org some day...

Here is the latest version with some bugfixes.
Especially the enabling of administer tool tips for (most of the) custom themes.
Enjoy..

JaapB’s picture

StatusFileSize
new229.68 KB

More fixes and stylized selection area.
Still hoping on a reply from the community...

Screenshot | Demo

zach harkey’s picture

I really like the adminstertooltip module so far. Any ideas how we might incorporate the Skinr module's "Edit Skin" task?

I thought I might be able to replace the Skinr cog with your administertooltip module, by inserting some code like the snippet below into some of the hook_administertooltip_block_links()

E.g., in hook_administertooltip_ENTITY_AREA():

    if (module_exists('skinr') && module_exists('skinr_ui') && user_access('access skinr')) {
      $admin_links[] = l(t('Edit Skin'), 'admin/build/skinr/edit/nojs/block/'. $variables['block']->module .'-'. $variables['block']->delta, array('attributes' => array('class' => 'skinr-link ctools-use-dialog ctools-use-dialog-processed')));
    } 

While this did add the "Edit Skin" link, it does not open in a modal dialog window, nor does it do all the cool AJAX live updating in the background like the Skinr cog link does.

The Skinr cog appears to be constructed entirely in Javascript (skinr.js) where it seems to be hopelessly isolated from a more general (and extensible) contextual admin menu solution.

Any thoughts?

(My kingdom for a decent contextual-admin.)

JaapB’s picture

I'll look into it!
Maybe I can add (copy) some of the javascript in a seperate submodule of some sort, and make it work together.
I'll let you know...

JaapB’s picture

Hey Zach,

I agree with you that that Skinr's way is really hard to implement within AdministerToolTip. I am currently revising some of the javascript in my ATT module, after which it should be easier to combine Skinr with ATT.

But... it would be great if this module could make it on the modules page on Drupal..

JaapB’s picture

Priority: Normal » Critical

Okey... it has been a MONTH...
I am not very psyched to "give back to the community" anymore..

Go here for the visual part of the module:
Screenshot | Demo

sun’s picture

Status: Needs review » Needs work
  • All user-submitted values and content need to be properly sanitized before output:
        $items[] = l(t('Edit content-type ') .'"'. drupal_ucfirst($node_type->name) .'"', 'admin/content/node-type/'. $variables['type'], array('query' => drupal_get_destination()));
    
  • All of the module's JavaScript should implement Drupal behaviors. Some JavaScript properties and functions are outside of the namespace of this module, which also applies to Drupal.xyz properties/functions.
  • The module contains a copy of the jQuery BeautyTips plugin, which exists as separate module on drupal.org. This module needs to add a dependency on the existing module, instead of duplicating the code (and maintenance).
  • The excanvas JavaScript library may not be committed to drupal.org CVS. (Apache license) All code must be licensed under the GPL.
  • Note that _administertooltip_extend() is based on a 3 year old tutorial, which suggests an architectural design that is considered bad today.
  • LICENSE.txt as well as .hg directories should not be contained nor committed.
JaapB’s picture

Status: Needs work » Needs review
StatusFileSize
new220.57 KB

-edit-
Did not see your reply when I posted, I'll post an updated version later on...
Attached file is not the right one! (cannot delete it)

sun’s picture

Status: Needs review » Needs work
JaapB’s picture

Status: Needs work » Needs review
StatusFileSize
new26.57 KB

Hi Sun,

Thanks for your review!
I have updated the module to fit your requests and comments, you can see the changes in the attached file..

But I do not agree with (or understand) your following comment:
"Note that _administertooltip_extend() is based on a 3 year old tutorial, which suggests an architectural design that is considered bad today."
The function just creates hooks for this module so it can be extended by other modules. I thought that that was the power of Drupal?
Am I implementing this in the wrong way? If so, can you point me in the right direction?

Thanks again for reviewing my module, I really appreciate the good look at it

Cheers, Jaap

avpaderno’s picture

Priority: Critical » Normal
Status: Needs review » Needs work
  1. As it is, the function _administertooltip_extend() is just a copy of the Drupal function module_invoke_all().
    function _administertooltip_extend($hook_name, $data = NULL) {
      $items = array();
      foreach (module_implements($hook_name) as $module) {
        if ($new = module_invoke($module, $hook_name, $data)) {
          $items = array_merge($items, $new);
        }
      }
      // Make sure we return an array.
      if (!is_array($items)) {
        return array();
      }
      return $items;
    }
    
    function module_invoke_all() {
      $args = func_get_args();
      $hook = $args[0];
      unset($args[0]);
      $return = array();
      foreach (module_implements($hook) as $module) {
        $function = $module .'_'. $hook;
        $result = call_user_func_array($function, $args);
        if (isset($result) && is_array($result)) {
          $return = array_merge_recursive($return, $result);
        }
        else if (isset($result)) {
          $return[] = $result;
        }
      }
    
      return $return;
    }
    

    Why isn't the code using module_invoke_all()?

  2. /**
     * Implementation of module_preprocess().
     */
    function administertooltip_preprocess(&$variables, $hook) {
    }
    

    The hook implementations are commented as Implementation of hook_<hook-name> (or more correctly Implements hook_<hook-name>).

  3. Drupal 6 used hook_preprocess_page(), hook_preprocess_user_profile(), etc; rather than having a unique function, it would be better to split the code in different functions.
JaapB’s picture

Status: Needs work » Needs review
StatusFileSize
new26.45 KB

Hey Kiam,

First my apologies for the late reply, I had a holiday without internet...

But thanks for your review!
Your comment about the module_invoke_all is much clearer now and I have adjusted my module accordingly.

I have also changed the comments to your suggestions.

Your third point I do not get completely. If I would crumble the "module_preprocess" into seperate functions I would have a lot of the same code multiple times?

Like:

function administertooltip_preprocess_user_profile(&$variables, $hook) {
  // Nothing to do here if the user is not permitted to access administer tool tip.
  if (!user_access('access administer tool tips')) {
    return;
  }
  // Is the administer tool tip enabled for this entity?
  if (!variable_get('administertooltip_'. $hook .'_enabled', 1)) {
    return;
  }
  $variables[$hook] .= theme('administertooltip', $hook, $variables);
}

function administertooltip_preprocess_user_picture(&$variables, $hook) {
  // Nothing to do here if the user is not permitted to access administer tool tip.
  if (!user_access('access administer tool tips')) {
    return;
  }
  // Is the administer tool tip enabled for this entity?
  if (!variable_get('administertooltip_'. $hook .'_enabled', 1)) {
    return;
  }
  $variables['picture'] .= theme('administertooltip', $hook, $variables);
}

Or am I getting it wrong?

Thanks for your insights!

avpaderno’s picture

Point #3 is only a suggestion, not something that really needs to be done.
To explain it better, I will add some more notes here.

  1. hook_preprocess_HOOK() implementations receive only an argument; $hook is not passed them, because they already know for which hook then are invoked.
  2. The reason to use different hooks instead of only one is to avoid conditional code inside them with the only purpose to alter variables basing on the hook currently being processed.
JaapB’s picture

Hi Kiam,

Interesting thought. If there was a way I could avoid "double code" in these preprocess-functions I would immediately cut that long function up in to single functions. But I do not see a great way to do that.

For instance, this gives to much "double code" for my taste, although it looks nicer ;-)
(draft code, needs proper function naming and comments)

/**
 * See if we may add an administer tool tip. 
 */
function _administertooltip_preprocess_access($hook) {
  // Nothing to do here if the user is not permitted to access administer tool tip.
  if (!user_access('access administer tool tips')) {
    return FALSE;
  }
  // Is the administer tool tip enabled for this entity?
  if (!variable_get('administertooltip_'. $hook .'_enabled', 1)) {
    return FALSE;
  }
  return TRUE;
}

/**
 * Implements hook_preprocess_block.
 */
function administertooltip_preprocess_block(&$variables) {
  if (_administertooltip_preprocess_access('block')) {
    $variables['block']->content .= theme('administertooltip', 'block', $variables);
  }
}

/**
 * Implements hook_preprocess_comment.
 */
function administertooltip_preprocess_comment(&$variables) {
  if (_administertooltip_preprocess_access('comment')) {
    $variables['links'] = ''; // Remove administration links.
    $variables['content'] .= theme('administertooltip', 'comment', $variables);
  }
}

I'll change it for now to see how it feels...

More interesting thoughts or comments?

JaapB’s picture

StatusFileSize
new26.58 KB

Latest version with seperate preprocess-functions and refurbished javascript.
Works very nice and easy now!

What do you think?

Module live in action:
Screenshot | Demo

JaapB’s picture

*bump*

JaapB’s picture

*re-bump*

sun’s picture

  $entities = _administertooltip_get_entities();
  foreach ($entities as $entity => $array) {
    if (is_file(dirname(__FILE__) . '/entities/' . $entity . '.administertooltip.inc')) {
      require_once( dirname(__FILE__) . '/entities/' . $entity . '.administertooltip.inc');
    }
  }

Needs to use drupal_get_path() instead. And, actually, you should use module_load_include() instead.

  if (drupal_load('module', 'jquery_ui')) {
    jquery_ui_add(array('ui.draggable', 'ui.droppable', 'ui.sortable'));
  }
  else {
    drupal_set_message(t("You need to have the jquery_ui module installed."), 'error');
  }

Requirements error handling should happen in hook_requirements(), not during runtime.

jquery_ui module is listed as dependency in the .info file. It therefore needs to be installed to install this module. Drupal loads all installed modules.

  if (function_exists('beautytips_add_beautytips')) {
    beautytips_add_beautytips();
  }
  else {
    drupal_set_message(t("You need to have the beautytips module installed."), 'error');
  }

Identical issue as with jquery_ui here.

    $current_theme = variable_get('theme_default', 'none');
    $block_regions = system_region_list($current_theme);

You have to properly initialize the theme in order to detect its regions. There are various modules (plus system.module in core) that allow to change the theme depending on request conditions, such as an administration theme.

---

Sorry, this module is quite large and hard to review and therefore takes it time. I'm running out of time now. Leaving as "needs review" so perhaps others will help reviewing.

avpaderno’s picture

Status: Needs review » Needs work

Let's start to fix what already reported.

JaapB’s picture

StatusFileSize
new26.53 KB

Hey Sun (and others)

I really appreciate your reviews, but I am afraid that you will forget my module between the thousands of others waiting for a review... therefor my "bump" here and there. I will try to control my impatience ;-)

Attached you will find the new version of ATT.
Nothing really changed except the fixes of the review above.

Again, thanks for the reviews!

JaapB’s picture

Status: Needs work » Needs review

forgot the status-change...

JaapB’s picture

*bump*

avpaderno’s picture

Assigned: Unassigned » avpaderno
Status: Needs review » Needs work
  • The points reported in this review are not in order or importance / relevance.
  • Most of the times I report the code that present an issue. In such cases, the same error can be present in other parts of the code; the fact I don't report the same issue more than once doesn't mean the same issue is not present in different places.
  • Not all the reported points are application blockers; some of the points I report are simple suggestions to who applies for a CVS account. For a list of what is considered a blocker for the application approval, see CVS applications review, what to expect. Keep in mind the list is still under construction, and can be changed to adapt it to what has been found out during code review, or to make the list clearer to who applies for a CVS account.
  1. The module doesn't implement hook_uninstall() to remove the Drupal variables it defines.
  2. /**
     * Implements hook_perm.
     *
     * @return array
     */
    function administertooltip_perm() {
      return array('access administer tool tips', 'dragndrop blocks', 'administer administer tool tips');
    }
    

    The first line should be Implements hook_perm().. For hook implementations, parameters and returned value are not described.
    I would use different permissions; administer administer tool tips is not the best.

  3. See http://drupal.org/coding-standards to understand how a module should be written. In particular, see how the code should be formatted.
JaapB’s picture

Status: Needs work » Needs review
StatusFileSize
new26.83 KB

1. Has been fixed in new release which was not uploaded here. New upload attached.

2. I took your previous advice apparently to litterally:
"The hook implementations are commented as Implementation of hook_ (or more correctly Implements hook_)."
I changed it again.

3. Everything is run trough the coder module on minor, there are no problems reported now.

avpaderno’s picture

Status: Needs review » Fixed
  1. function administertooltip_perm() {
      return array('access administer tooltips', 'drag and drop blocks', 'configure administer tooltips');
    }
    

    The last permission should be administer tooltips.

  2. The code is not completely formatted as reported by the coding standards.
  3. The JavaScript namespaces Drupal.ATT_DND and Drupal.ATT should be named to something closer to the name of the module.

Thank you for your contribution! I am going to update your account.

These are some recommended readings to help with excellent maintainership:

You can find more contributors chatting on the IRC #drupal-contribute channel. So, come hang out and stay involved.
Thank you, also, for your patience with the review process.
Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.

I thank all the dedicated reviewers as well.

JaapB’s picture

StatusFileSize
new26.84 KB

Thanks again for the review!

"2. The code is not completely formatted as reported by the coding standards."
- this still needs to be fixed, I'll work on it tomorrow

The rest has been modified according to your review.
(also 2 minor bugfixes)

avpaderno’s picture

@JaapB: Thank you for reporting here the changed code. Your CVS application has been approved; you can commit the code in CVS, now. :-)

JaapB’s picture

NICE! thanks!

I have created the projectpage here: http://drupal.org/project/administertooltip
The code will be there in a jiff...

Status: Fixed » Closed (fixed)
Issue tags: -Module review

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

avpaderno’s picture

Component: Miscellaneous » new project application
Issue summary: View changes