How to show only populated menu tabs in Drupal? - drupal

In evaluating the Invite and Support modules for Drupal recently, we realized the default tab navigation is not the most user friendly. In particular, each module has a page of tabs that show the various categories of invitations or support tickets (pending, cancelled, etc). For developers, it's easiest to pre-define all the tabs, but from a user standpoint, it makes more sense to only be offered the tabs that contain content.
I assume it's possible to run queries to check which tabs should be displayed for a particular user and change the menus using hook_menu_alter. However, is that the best way to do it or will that cause problems with Drupal's menu caching? Is there a better way?

The answer by jhedstrom is correct, but I'm not that convinced that dynamically showing/hiding local tasks results in better UX, that sounds kinda confusing to me.
Instead, my suggestion would be to use a title callback (which can be added with the same hook_menu_alter() and show the number of things inside that specific tab. That is what I for example use for Privatemsg to show the number of unread messages.
See privatemsg_title_callback() for an example and hook_menu for more information about title callbacks in general.

If you want to selectively remove tabs in a dynamic way (eg, one node gets a tab, while another does not), you won't be able to use hook_menu_alter() because that only has an effect when the menu cache is being built. However, you can do this by overriding the menu access callback. If access to a tab is denied, it won't be displayed.
For example, to override a node tab, you might do something like this:
function mymodule_menu_alter(&$items) {
$item['node/%node/foo']['access callback'] = 'mymodule_override_access';
}
function mymodule_override_access($node) {
// Perform queries, logic, etc to determine if content exists at node/nid/foo.
// Return false if there is no content, otherwise fall through to the original
// access callback function.
}

Related

Drupal 6, giving user ability to create microsites

I built a website that allows a user to create event pages with schedules etc... But now I want to give more options which can be used to build more of a minisite or microsite. So along with the usual options of adding a gallery, description etc.. I want them to be able to add a sub menu, and a custom background. I think the background is easy. However, for the submenu I don't really want to give access to the menu options. I would like to still use nice menu though.
I would love some suggestions as to the best way of adding these features while making it really intuitive for the users. Something like a Microsite node that allows everything to be set on one page perhaps?
Have you looked at Open Atrium? http://openatrium.com/
This is a Drupal distribution that lets you create microsites.

How to serve different cached versions of a page depending on a cookie in Drupal?

The task is relatively straightforward:
A Drupal website displays a list of articles with thumbnails. Some visitors would like to view it without images by clicking on a button/link and have that preference saved.
e.g. http://patterntap.com/collections/index/
The problem is all visitors are anonymous and given certain traffic, page cache is enabled.
My idea was to use some simple JavaScript to set a cookie, refresh the page and depending on the cookie values (or its presence/absence) display or hide the images.
Except Drupal serves cached pages quite early and the only quick way to modify the cached version that I could find is by hacking includes/bootstrap.inc and add a custom class to the body classes then hide the images with css.
A very wrong approach, I know. But I wonder if there is a way to save different versions of a page and serve the correct version?
Edit:
need to keep the same uri
the js to show/hide the images without reload and set the cookie is already in place
hook_boot() is not really called for cached pages, so can't do it via custom module
.htaccess mods?
Edit/solution:
In the end went with Rimian's suggestion. But it is possible to accomplish the task using our own cache.inc implementation as seen in the Mobile Tools module. Specifically, by extending cache.inc and updating settings.php to include
$conf['page_cache_fastpath'] = FALSE;
$conf['cache_inc'] = 'path/to/my/module/my_module_cache.inc';
So let me get this right. You wanna hide some images on a cached page if the user chooses to?
Why don't you write some jQuery or javascript and load that into your cached page with all the rest of the document?
Then, the client/browser would decide to run your script and hide images depending on some parameters you passed along with the request to that page or in the cookie? The script gets cached and only runs when you call it.
If you were hacking the bootstrap for something like that you'd really need to be rethinking what you were doing. Crazy! :)
Also take a look at cache_get and cache_set:
http://api.drupal.org/api/drupal/includes--cache.inc/6
I'm not sure I 100% understand what you are trying to do but here are my thoughts. One of your root problems is that you are trying to access what is essentially different content at the same uri.
If this is truly what you want to do, then Rimian's suggestion of checking out chache_get and chache_set may be worthwhile.
Personally, it seems cleaner to me to have your "with thumbnails" and "without thumbnails" be accessed via different uri's. Depending on exactly what you are wanting to accomplish, a GET variable my be an even better way to go. With either of these two options you would hide or show your thumbnails at the theme layer. Pages with different paths or get variables would get cached separately.
If you want the visitor to be able to switch views without a page reload, then jQuery and a cookie would probably suite your needs. This wouldn't require a page reload and switching back and forth would be quite simple.

How can I stop the Flash privacy popup from occurring twice on a page?

My web-app records users via webcam and microphone. I want to use HTML/JS for the controls and content, so I created two separate Flex modules:
* A "Webcam Setup" module that lets you choose your camera and mic input devices
* A "record" module that lets the user record and submit the recording
When I embed either of these on the page, since they access the user's Camera/Mic object, Flash shows the Privacy dialog that says "[mysite] is requesting access to your camera and microphone. If you click Allow, you may be recorded."
The problem is, if I answer Yes in the Setup module, and later add the Record module to the page using Javascript, it again shows the Privacy dialog.
Is there a way to avoid the second privacy popup?
I would think that saying "Yes" for [mysite] would store that permission for at least that session, but apparently not.
What I've tried
I tried combining them into one SWF, adding it to the page once and moving the DOM element with jQuery's append() function when needed. When I move it, however, it reloads and asks me again.
Imagine if [mysite] was, say, blogger.com or livejournal.com (or, if it were still around, geocities.com). Would you want a "yes" response on that site to be good for every page under that domain?
Rememeber, just because you promise (cross your heart & hope to die) not to abuse the security hole you request, doesn't mean they can allow you to have that security hole.
Eventually, I found a usable workaround, similar to what I originally tried (above).
I combined the setup and record modules into one SWF. I first show the setup screen. When the user hits the Continue button on my page, Javascript calls a function in the SWF to swap to the Record screen.
I then move the <div> containing the Flash object to another location on page using absolute positioning, and resize the object.
Previously, I was trying to use jQuery's append() function to move the div within the DOM, and that was causing the SWF to reload. Just changing position and size does actually work.
You could build the "record" component to simply send and receive signals using an API you've created for your "setup" component (which has already been authorized, meaning one auth & two swfs) by using the LocalConnection class:
http://livedocs.adobe.com/flex/3/langref/flash/net/LocalConnection.html
This seems far closer to best practice than the other implementations mentioned, which smell a bit hacky and would probably confuse anyone who may inherit the codebase in the future.

Drupal, Views.. how to display views list + complete node, interactively?

I'm using Views in Drupal to show node teasers. I would like now to show the complete node on the left side of my page, nearby the Views, and update it when the user click on a different teaser (better using AJAX).
what's the best method to implement it. I was considering to use a lightbox, but it a bit complex (a lot of complications... such as parsing the content with javascript again.. etc).
See screenshot: http://dl.dropbox.com/u/72686/viewsAndNode.png
Thanks
A quick and dirty approach would be to use an iframe to hold the node content. Users would then be able to switch between nodes without reloading the page, which is I assume your goal. I don't think there is away to achieve what you are trying to do with views out of the box. Have you looked into using panels?
Here's what might be a clean way to do it, of course in drupal there's always many ways to accomplish things.
Providing the content for the ajax call
Install the services module
Setup a service that provides your node as you want it to be displayed
Create the placeholder for your content
Install the Panels Module
Create a empty fixed width panel to contain the node you want to load
Load the view into an adjacent panel
In your controlling view
Add a PHP view header and use (drupal_add_js('script.js')) to add a custom js file to the page. or add this to a custom module, or even your theme.
Re-Write your view node links to help put the js events together
Setup your javascript events
Use add_js to add a custom javascript js file to the page
In the custom js add an event to the view links that will poll the services module and load the node into the placeholder panel
I've solved using the lightbox, and just removing the html code I don't need from the node template with php if the parameter "lightbox=true" is passed with the link.

Is there a generic way to implement an ConfirmIfDirty feature for a web page?

On stackoverflow, and other websites, if you start making a change to form elements and then you try to navigate away from the page, you will get a confirmation message asking if you are sure you want to discard your changes.
This seems relatively easy to do by hand, but impractical to apply across an entire site. Is there any generic solution that can be plopped onto a page as a control (or even jQuery plugin) which will track IsDirty for all fields (without having to specify each field by hand)?
You can use the window.onbeforeunload event.
See also How can I override the OnBeforeUnload dialog and replace it with my own?
A possiblity would be to clone a selection of all your inputs when the page is loaded (and data into it as well).
You could then do a compare as desribed here:
http://chris-barr.com/entry/comparing_jquery_objects/
Word of warning though, this may be costly, performance wise.

Resources