/[drupal]/contributions/modules/drupalorg/drupalorg_crosssite/drupalorg_crosssite.module
ViewVC logotype

Contents of /contributions/modules/drupalorg/drupalorg_crosssite/drupalorg_crosssite.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.36 - (show annotations) (download) (as text)
Fri Sep 4 09:12:41 2009 UTC (2 months, 3 weeks ago) by drumm
Branch: MAIN
CVS Tags: HEAD
Changes since 1.35: +7 -1 lines
File MIME type: text/x-php
Move profile tab to drupalorg module
1 <?php
2 // $Id: drupalorg_crosssite.module,v 1.35 2009/09/03 15:11:49 drumm Exp $
3
4 /**
5 * @file
6 * Cross-site functionality for Drupal.org subsites, which should be enabled
7 * on more subsites.
8 */
9
10 // == Core hooks ===============================================================
11
12 /**
13 * Implementation of hook_preprocess_page().
14 *
15 * Add header, footer and content menu data to the page variables.
16 */
17 function drupalorg_crosssite_preprocess_page(&$vars, $hook) {
18 global $user;
19
20 // Site hostnames for the sites we use.
21 $sites = drupalorg_crosssite_menu_sites();
22
23 // == Build the header navigation
24
25 // Hardcoded list of menu items. These are not supposed to have any indication
26 // of the active item, since the page title and submenus have that indication.
27 // Also, we should not let people edit these, since they should be standard
28 // among all the subsites. So this is why they are here.
29 $nav_header_links = array(
30 'getting-started' => array('href' => 'start', 'title' => t('Get Started'), '#site' => 'main'),
31 'forum' => array('href' => 'community', 'title' => t('Community & Support'), '#site' => 'main'),
32 'handbooks' => array('href' => 'documentation', 'title' => t('Documentation'), '#site' => 'docs'),
33 'project' => array('href' => 'download', 'title' => t('Download & Extend'), '#site' => 'project'),
34 'marketplace' => array('href' => 'services', 'title' => t('Marketplace'), '#site' => 'main'),
35 'about' => array('href' => 'about', 'title' => t('About'), '#site' => 'main'),
36 );
37 // Make all external links right.
38 $nav_header_links = drupalorg_crosssite_menu_absolute_links($nav_header_links);
39 // Theme as links, and avoid class="links" on it.
40 $vars['nav_header'] = theme('links', $nav_header_links, array());
41
42 // == Build the footer navigation
43
44 $nav_footer_links = array(
45 array(
46 'news' => array('href' => 'news', 'title' => t('Drupal News'), '#site' => 'main'),
47 'planet' => array('href' => 'planet', 'title' => t('Planet Drupal'), '#site' => 'main'),
48 'association' => array('href' => '', 'title' => t('Association'), '#site' => 'association'),
49 'jobs' => array('href' => 'jobs', 'title' => t('Jobs'), '#site' => 'groups'),
50 ),
51 array(
52 'getting-started' => array('href' => 'getting-started', 'title' => t('Getting Started'), '#site' => 'main'),
53 'download-core' => array('href' => 'project/Drupal+project', 'title' => t('Downloading Drupal'), '#site' => 'project'),
54 'get-involved' => array('href' => '', 'title' => t('Get Involved'), '#site' => 'main'),
55 ),
56 array(
57 'download' => array('href' => 'project', 'title' => t('Download & Extend'), '#site' => 'project'),
58 'download-core' => array('href' => 'project/Drupal+project', 'title' => t('Drupal core'), '#site' => 'project'),
59 'download-modules' => array('href' => 'project/Modules', 'title' => t('Modules'), '#site' => 'main'),
60 'download-themes' => array('href' => 'project/Themes', 'title' => t('Themes'), '#site' => 'main'),
61 'download-profiles' => array('href' => 'project/Installation+profiles', 'title' => t('Installation Profiles'), '#site' => 'main'),
62 ),
63 array(
64 'events' => array('href' => 'events', 'title' => t('Events'), '#site' => 'groups'),
65 'drupalcon' => array('href' => 'events?filter0%5B%5D=drupalcon', 'title' => t('Drupalcon'), '#site' => 'groups'),
66 'groups-join' => array('href' => '', 'title' => t('Join a Local Group'), '#site' => 'groups'),
67 'training' => array('href' => 'events?filter0%5B%5D=training', 'title' => t('Training'), '#site' => 'groups'),
68 'druplicon' => array('href' => 'druplicon', 'title' => t('Druplicon'), '#site' => 'main'),
69 ),
70 array(
71 'col5item1' => array('href' => 'col5item1', 'title' => t('col5item1'), '#site' => 'main'),
72 'col5item2' => array('href' => 'col5item2', 'title' => t('col5item2'), '#site' => 'main'),
73 'col5item3' => array('href' => 'col5item3', 'title' => t('col5item3'), '#site' => 'main'),
74 ),
75 );
76
77 $vars['nav_footer'] = '';
78 foreach ($nav_footer_links as $num => $links_column) {
79 // Make all external links right.
80 $links_column = drupalorg_crosssite_menu_absolute_links($links_column);
81
82 // Add alpha and omega class to first and last item.
83 $alpha_omega = '';
84 if ($num == 0) {
85 $alpha_omega = ' alpha';
86 }
87 else if ($num == count($nav_footer_links) - 1) {
88 $alpha_omega = ' omega';
89 }
90
91 // Theme as links, and avoid class="links" on it.
92 $vars['nav_footer'] .= '<div class="grid-footer'. $alpha_omega .'">'. theme('links', $links_column, array()) .'</div>';
93 }
94
95 // Add content header navigation.
96 drupalorg_crosssite_content_menu($vars);
97
98 // Add page tool navigation.
99 $page_tools = module_invoke_all('drupalorg_crosssite_page_tools');
100 if (count($page_tools) > 0) {
101 $vars['page_tools'] = theme('links', $page_tools);
102 }
103
104 // == Nav masthead links
105
106 $nav_masthead_links = array(
107 'homepage' => array('href' => 'home', 'title' => t('Drupal Homepage'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^(home|)/?$')),
108 'dashboard' => array('href' => 'dashboard', 'title' => t('Your dashboard'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^dashboard(/|$)')),
109 );
110 $userinfo = '';
111 if ($user->uid == 0) {
112 $nav_masthead_links['login-register'] = array('href' => 'user', 'title' => t('Login / Register'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^user(/|$)'));
113 }
114 else {
115 // If not the main site (or a test server), provide logout link to the main site, since
116 // that would log us out of the single-sign-on-domain. @todo
117 // $single_sign_on_prefix = drupalorg_crosssite_menu_site('main') ? '' : 'http://drupal.org/';
118
119 // Add user page link and logout link.
120 $userinfo = '<div id="userinfo">'. l(t('Logged in as @username', array('@username' => $user->name)), 'user') .' '. l(t('Logout'), 'logout') .'</div>';
121 }
122 // Make all external links right.
123 $nav_masthead_links = drupalorg_crosssite_menu_absolute_links($nav_masthead_links);
124 // Theme as links, and avoid class="links" on it.
125 $vars['nav_masthead'] = theme('links', $nav_masthead_links, array()) . $userinfo;
126 }
127
128 /**
129 * Content for the content top menu.
130 *
131 * We implement this as "custom menus", since we need to have cross-site menu
132 * items in some cases, and having these sycned across all subsites would be
133 * painful (read: menu items would have different URLs and menu ids on subsites,
134 * since an API link on the docs site would link out to API while a docs link
135 * on the API would link out to the docs site).
136 */
137 function drupalorg_crosssite_content_menu(&$vars) {
138 global $user;
139
140 // Specify the high level matching criteria for each menu and let others put
141 // in more menus.
142 $nav_content_areas = array(
143 'documentation' => drupalorg_crosssite_menu_site('api') || drupalorg_crosssite_menu_type('docs', array('book')) || drupalorg_crosssite_menu_path('docs', '^(documentation|handbooks)(/|$)'),
144 'downloads' => drupalorg_crosssite_menu_path('project', '^(project|download)(/|$)') || drupalorg_crosssite_menu_type('project', array('project_project', 'project_issue', 'project_release')),
145 // Events appear at here and as an individual tab list. Commented out from here.
146 'community' => drupalorg_crosssite_menu_path('main', '^(irc|mailing-lists|profile|forum|community)(/|$)'), // || drupalorg_crosssite_menu_path('groups', '^events'),
147 'jobs' => drupalorg_crosssite_menu_path('groups', '^(jobs)(/|$)'),
148 'association' => drupalorg_crosssite_menu_site('association'),
149 'events' => drupalorg_crosssite_menu_path('groups', '^events(/|$)'),
150 'druplicon' => drupalorg_crosssite_menu_path('main', '^(node/9068|druplicon)(/|$)'),
151 'dashboard' => drupalorg_crosssite_menu_path('main', '^(dashboard|user/'. $user->uid .')(/|$)'),
152 );
153
154 // Theoretically, the matching criteria made one of the areas win (have TRUE as
155 // the array value). If there are two menus to display on the same path, we
156 // are in trouble, since we only have one menu displayed per path. Fix the above
157 // matching in that case. (This will pick the first matched in that case).
158 $matched_menu = array_search(TRUE, $nav_content_areas);
159
160 //Identify sections names/titles to be displayed above content area menus
161 $section_names = array(
162 'downloads' => 'Download and Extend',
163 'documentation' => 'Documentation',
164 'community' => 'Community &amp; Support',
165 'dashboard' => '',
166 );
167 //set the section_name variable to be output in page.tpl.php
168 if (isset($section_names[$matched_menu])) {
169 $vars['section_name'] = $section_names[$matched_menu];
170 }
171
172 // Now ask for all the menu items for the matched menu. Let modules add in
173 // menu items (eg. in case of dashboard module adding items we don't know about).
174 $nav_content_links = module_invoke_all('drupalorg_crosssite_content_menu_items', $matched_menu);
175
176 if (count($nav_content_links)) {
177 // Make all external links right.
178
179 $nav_content_links = drupalorg_crosssite_menu_absolute_links($nav_content_links);
180
181 //check the links to see if it is an active link
182 foreach ($nav_content_links as $key => $link) {
183 $class = $key;
184 if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))
185 && (empty($link['language']) || $link['language']->language == $language->language)) {
186 //this is an active link/tab, therefore we don't want
187 //to display the page title - used in page.tpl.php
188 $vars['matched_content_link'] = TRUE;
189 }
190 }
191
192 // Theme the links for the page, bypassing class="links".
193 $vars['nav_content'] = theme('links', $nav_content_links, array());
194 $vars['nav_content_class'] = ' class="nav-content-'. $matched_menu .'"';
195 return;
196 }
197
198 // Else just return an empty content nav menu.
199 $vars['nav_content'] = $vars['nav_content_class'] = '';
200 }
201
202 /**
203 * Implementation of hook_drupalorg_crosssite_content_menu_items().
204 *
205 * Return a list of menu items for the given menu with metadata on their
206 * associated site and whether they are active at the moment.
207 */
208 function drupalorg_crosssite_drupalorg_crosssite_content_menu_items($matched_menu) {
209 switch ($matched_menu) {
210
211 // REAL cross-site.
212 case 'documentation':
213 return array(
214 'home' => array('href' => 'documentation', 'title' => t('Docs Home'), '#site' => 'docs', '#active' => drupalorg_crosssite_menu_type('docs', array('book')) || drupalorg_crosssite_menu_path('docs', '^(documentation(?!/index|/recent)|handbooks(/|$))')),
215 'api' => array('href' => '', 'title' => t('API'), '#site' => 'api', '#active' => drupalorg_crosssite_menu_site('api')),
216 'index' => array('href' => 'documentation/index', 'title' => t('Index'), '#site' => 'docs', '#active' => drupalorg_crosssite_menu_path('docs', '^(documentation/index)(/|$)')),
217 'recent' => array('href' => 'documentation/recent', 'title' => t('Recently updated'), '#site' => 'docs', '#active' => drupalorg_crosssite_menu_path('docs', '^(node/23192)(/|$)')),
218 );
219
220 // Just on the project site.
221 case 'downloads':
222 return array(
223 // All are exact paths and so theme('links') will make them gain active
224 // classes when on the projects site. Therefore no need for #active.
225 'home' => array('href' => 'download', 'title' => t('Download & Extend Home'), '#site' => 'project'),
226 'core' => array('href' => 'project/drupal', 'title' => t('Drupal Core'), '#site' => 'project'),
227 'modules' => array('href' => 'project/modules', 'title' => t('Modules'), '#site' => 'project'),
228 'themes' => array('href' => 'project/themes', 'title' => t('Themes'), '#site' => 'project'),
229 'translations' => array('href' => 'project/translations', 'title' => t('Translations'), '#site' => 'project'),
230 'theme-engine' => array('href' => 'project/theme engines', 'title' => t('Theme Engines'), '#site' => 'project'),
231 'install-profiles' => array('href' => 'project/installation profiles', 'title' => t('Installation Profiles'), '#site' => 'project'),
232 );
233
234 // REAL cross-site.
235 case 'community':
236 return array(
237 'home' => array('href' => 'community', 'title' => t('Community Home'), '#site' => 'main'),
238 'local-groups' => array('href' => '??', 'title' => t('Local Groups'), '#site' => 'groups'),
239 'online-groups' => array('href' => '??', 'title' => t('Online Groups'), '#site' => 'groups'),
240 'chat' => array('href' => 'irc', 'title' => t('Chat'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^irc(/|$)')),
241 // Does not make sense, see question to Mark at http://groups.drupal.org/node/19010
242 // 'events' => array('href' => 'events', 'title' => t('Events'), '#site' => 'groups'),
243 'lists' => array('href' => 'mailing-lists', 'title' => t('Mailing lists'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^mailing-lists(/|$)')),
244 'members' => array('href' => 'profile', 'title' => t('Member directory'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^profile(/|$)')),
245 'forum' => array('href' => 'forum', 'title' => t('Forum'), '#site' => 'main', '#active' => drupalorg_crosssite_menu_path('main', '^forum(/|$)') || drupalorg_crosssite_menu_type('main', array('forum'))),
246 );
247
248 // Just on the jobs site. Will need dynamic listing based on numbers.
249 case 'jobs':
250 return array(
251 'latest' => array('href' => 'jobs', 'title' => t('Latest'), '#site' => 'groups'),
252 'developers' => array('href' => '??', 'title' => t('Developers (#)'), '#site' => 'groups'),
253 'designers' => array('href' => '??', 'title' => t('Designers (#)'), '#site' => 'groups'),
254 'writers' => array('href' => '??', 'title' => t('Writers (#)'), '#site' => 'groups'),
255 );
256
257 // Just on the association site.
258 case 'association':
259 return array(
260 'home' => array('href' => '', 'title' => t('Association Home'), '#site' => 'association'),
261 'blogs' => array('href' => 'blogs', 'title' => t('Blogs'), '#site' => 'association'),
262 'about' => array('href' => 'about', 'title' => t('About'), '#site' => 'association'),
263 'donate' => array('href' => 'civicrm/contribute/transact?reset=1&id=8', 'title' => t('Donate'), '#site' => 'association'),
264 'membership' => array('href' => 'membership', 'title' => t('Memberships'), '#site' => 'association'),
265 'press' => array('href' => 'press', 'title' => t('Press'), '#site' => 'association'),
266 'faq' => array('href' => 'faq', 'title' => t('FAQ'), '#site' => 'association'),
267 'staff' => array('href' => 'about/staff', 'title' => t('Staff'), '#site' => 'association'),
268 'contact' => array('href' => 'contact', 'title' => t('Contact'), '#site' => 'association'),
269 // Was on the mockups but makes no sense.
270 //'home' => array('href' => '', 'title' => t('Login')),
271 );
272
273 // Just on the events site. Could possibly do the same dynamic
274 // stuff as jobs for consistency (counting number of events).
275 case 'events':
276 return array(
277 'latest' => array('href' => 'events', 'title' => t('Latest'), '#site' => 'groups'),
278 'local' => array('href' => 'events?filter0%5B%5D=usergroup', 'title' => t('Local Group Meeting'), '#site' => 'groups'),
279 'training' => array('href' => 'events?filter0%5B%5D=training', 'title' => t('Training'), 'site' => '#groups'),
280 'regional' => array('href' => 'events?filter0%5B%5D=regional', 'title' => t('Regional Conference'), '#site' => 'groups'),
281 'drupalcon' => array('href' => 'events?filter0%5B%5D=drupalcon', 'title' => t('Drupalcon'), '#site' => 'groups'),
282 'virtual' => array('href' => 'events?filter0%5B%5D=virtual', 'title' => t('Virtual Meeting'), '#site' => 'groups'),
283 );
284
285 // Just on the main website.
286 case 'druplicon':
287 return array(
288 'home' => array('href' => '??', 'title' => t('Druplicon Home'), '#site' => 'main'),
289 'about' => array('href' => 'druplicon', 'title' => t('About Druplicon'), '#site' => 'main'),
290 'download' => array('href' => 'node/9068', 'title' => t('Download Druplicon'), '#site' => 'main'),
291 'other' => array('href' => '??', 'title' => t('Other Druplicons'), '#site' => 'main'),
292 );
293
294 case 'dashboard':
295 global $user;
296 $links = dashboard_user_tabs();
297 array_splice($links, -1, 0, array('dashboard-profile' => array(
298 'title' => t('Profile'),
299 'href' => 'user/'. $user->uid,
300 'attributes' => array('class' => 'nav-tab'),
301 )));
302 foreach (array_keys($links) as $key) {
303 $links[$key]['#site'] = 'main';
304 if (isset($links[$key]['#href'])) {
305 $links[$key]['#active'] = drupalorg_crosssite_menu_path('main', '^' . $links[$key]['#href'] . '($|/)');
306 }
307 }
308 return $links;
309 }
310 }
311
312 // == API functions ============================================================
313
314 /**
315 * Which site is which URL?
316 *
317 * We have multiple keys for different functionality, so in case we need to
318 * break these out, we can quickly swap these URLs and be done with updating
319 * the navigation by deploying the new version of this module across all
320 * subsites.
321 */
322 function drupalorg_crosssite_menu_sites() {
323 return array(
324 'docs' => 'drupal.org',
325 'main' => 'drupal.org',
326 'project' => 'drupal.org',
327 'api' => 'api.drupal.org',
328 'association' => 'association.drupal.org',
329 'groups' => 'groups.drupal.org',
330 );
331 }
332
333 /**
334 * Check whether we are on the specified site.
335 *
336 * @param $site_key
337 * One of the sitekeys as defined in drupalorg_crosssite_menu_sites().
338 * @return
339 * TRUE if on the site specified by $site_key.
340 * @todo
341 * Investigate testing domain indentification for subsites.
342 */
343 function drupalorg_crosssite_menu_site($site_key) {
344 static $site = NULL;
345 static $sites = NULL;
346
347 if (!isset($site)) {
348 list($site) = explode(':', $_SERVER['HTTP_HOST']);
349 $sites = drupalorg_crosssite_menu_sites();
350 }
351
352 // If we have this site defined and the host name matches, we are on that site.
353 // If there is no site with our current site name and the main site is requested,
354 // we also fall back on saying we are on the site, since then we are on a developer
355 // site for drupal.org.
356 return (isset($sites[$site_key]) && ($sites[$site_key] == $site)) || (!isset($sites[$site]) && in_array($site_key, array('main', 'project', 'docs')));
357 }
358
359 /**
360 * Check whether we are viewing any of the specified node types on the given site.
361 *
362 * @param $site_key
363 * One of the sitekeys as defined in drupalorg_crosssite_menu_sites().
364 * @param $node_types
365 * An array of possible node types to check for.
366 * @return
367 * TRUE if on the site specified by $site_key, looking at a node of any of the
368 * types specified in $node_types.
369 */
370 function drupalorg_crosssite_menu_type($site_key, $node_types) {
371 // menu_get_object() gets us the node, if we have a node loaded on the path.
372 if (drupalorg_crosssite_menu_site($site_key) && ($node = menu_get_object())) {
373 return in_array($node->type, $node_types);
374 }
375 }
376
377 /**
378 * Check whether we are viewing any of the specified paths on the given site.
379 *
380 * @param $site_key
381 * One of the sitekeys as defined in drupalorg_crosssite_menu_sites().
382 * @param $path_regex
383 * A Per regular expression to match against the current path.
384 * @return
385 * TRUE if on the site specified by $site_key, looking at a path matching
386 * $path_regex.
387 * @todo
388 * Investigate path alias matching. This will probably be broken a bit in
389 * that regard for now.
390 */
391 function drupalorg_crosssite_menu_path($site_key, $path_regex = '') {
392 // menu_get_object() gets us the node, if we have a node loaded on the path.
393 if (drupalorg_crosssite_menu_site($site_key)) {
394 if (empty($path_regex)) {
395 // We need to match the front page.
396 return (empty($_GET['q']));
397 }
398 else {
399 // Use the full preg_match.
400 return preg_match('#'. $path_regex .'#', $_GET['q']);
401 }
402 }
403 }
404
405 /**
406 * Make sure outside links are absolute and add "active" classes as required.
407 *
408 * @param $links
409 * List of links array as expected by theme('links') with #site and
410 * #active keys for the individual links to specify which site to point
411 * the link to and whether the item is active.
412 *
413 * - For possible #site values, @see drupalorg_crosssite_menu_sites().
414 * - #active can be built with @see drupalorg_crosssite_menu_path(),
415 * @see drupalorg_crosssite_menu_site() and
416 * @see drupalorg_crosssite_menu_type() (as well as possibly
417 * @see user_access() and friends, if you made sure the link will be
418 * local, so you can do local access checks against it).
419 *
420 * @return
421 * The modified link array.
422 */
423 function drupalorg_crosssite_menu_absolute_links($links) {
424 static $sites = NULL;
425 if (!isset($sites)) {
426 $sites = drupalorg_crosssite_menu_sites();
427 }
428
429 $activated_links = array();
430 foreach ($links as $key => $link) {
431 // If we are not on the given site, convert the link to an absolute link
432 // to the given site.
433 if (isset($link['#site']) && !drupalorg_crosssite_menu_site($link['#site'])) {
434 $link['href'] = 'http://'. $sites[$link['#site']] .'/'. $link['href'];
435 }
436 // Otherwise, it might be an active link still, so add on the active class,
437 // if we know #active was defined TRUE.
438 elseif (!empty($link['#active'])) {
439 // theme('link') uses the key as class, so add active class that way.
440 $key = $key .' active';
441 }
442 // Add a tab class for styling.
443 if (isset($link['attributes']['class'])) {
444 $link['attributes']['class'] .= ' nav-tab';
445 }
446 else {
447 $link['attributes']['class'] = 'nav-tab';
448 }
449 $activated_links[$key] = $link;
450 }
451 return $activated_links;
452 }

  ViewVC Help
Powered by ViewVC 1.1.2