/[drupal]/contributions/modules/weblinks/weblinks.module
ViewVC logotype

Contents of /contributions/modules/weblinks/weblinks.module

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


Revision 1.87 - (show annotations) (download) (as text)
Mon Jul 20 16:52:34 2009 UTC (4 months ago) by nancyw
Branch: MAIN
CVS Tags: HEAD
Changes since 1.86: +808 -966 lines
File MIME type: text/x-php
Update HEAD to start 7.x
1 <?php
2 // $Id: weblinks.module,v 1.86.2.85.2.58 2009/07/20 02:56:13 nancyw Exp $
3
4 /**
5 * @file
6 * Enable submission and display of categorized web links.
7 * Drupal 6 Version
8 */
9
10 if (module_exists('token')) {
11 include_once(drupal_get_path('module', 'weblinks') .'/token_weblinks.inc');
12 }
13 if (!module_exists('weight')) {
14 include_once(drupal_get_path('module', 'weblinks') .'/weblinks.weight.inc');
15 }
16
17 /**
18 * Implementation of hook_help().
19 */
20 function weblinks_help($path, $args) {
21 switch ($path) {
22 case 'admin/modules#description':
23 case 'admin/help#weblinks':
24 return '<p>'. t('Enables the submission and display of categorized links to other web sites.') .'</p>';
25
26 case 'node/%':
27 $node = node_load($args[1]);
28 if ($node->type != 'weblinks') {
29 return NULL;
30 }
31 // Fall through to get css.
32
33 case 'weblinks/%':
34 case 'weblinks':
35 drupal_add_css(drupal_get_path('module', 'weblinks') .'/weblinks.css');
36 return theme('weblinks_pagedesc');
37 }
38 }
39
40 /**
41 * Implementation of hook_perm().
42 */
43 function weblinks_perm() {
44 return module_invoke_all('weblinks_perm');
45 }
46
47 /**
48 * Implementation of hook_weblinks_perm().
49 */
50 function weblinks_weblinks_perm() {
51 return array(
52 'access web links',
53 'create weblinks',
54 'edit own weblinks',
55 'view my weblinks',
56 'edit group weblinks',
57 'administer weblinks',
58 'view click count',
59 );
60 }
61
62 /**
63 * Implementation of hook_node_info().
64 */
65 function weblinks_node_info() {
66 return array(
67 'weblinks' => array(
68 'name' => t('Web Links'),
69 'description' => t('Create a new web link.'),
70 'has_title' => TRUE,
71 'title_label' => t('Link Name'),
72 'has_body' => TRUE,
73 'body_label' => t('Link Description'),
74 'module' => 'weblinks',
75 )
76 );
77 }
78
79 /**
80 * Implementation of hook_init().
81 */
82 function weblinks_init() {
83 global $base_path;
84 // The menu title is not correct if the menu item has been moved to
85 // a menu other than Navigation. See http://drupal.org/node/184955.
86 if (arg(0) == 'weblinks') {
87 $active_trail = menu_set_active_trail();
88 foreach ($active_trail as $key => $item) {
89 if ($item['path'] == 'weblinks') {
90 $active_trail[$key]['title'] = _weblinks_get_menu_title();
91 }
92 }
93 menu_set_active_trail($active_trail);
94 }
95 }
96
97 /**
98 * Get the correct menu title.
99 * This is a helper function for hook_init and hook_view.
100 */
101 function _weblinks_get_menu_title() {
102 return t(db_result(db_query("SELECT link_title FROM {menu_links} WHERE link_path = 'weblinks'")));
103 }
104
105 /**
106 * Implementation of hook_form().
107 */
108 function weblinks_form(&$node) {
109 $type = node_get_types('type', $node);
110
111 if ($type->has_title) {
112 $form['title'] = array(
113 '#type' => 'textfield',
114 '#title' => check_plain($type->title_label),
115 '#required' => TRUE,
116 '#maxlength' => 255,
117 '#default_value' => $node->title,
118 '#weight' => -5,
119 );
120 }
121 if ($type->has_body) {
122 $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
123 $form['body_field']['body']['#rows'] = 5;
124 $form['body_field']['body']['#default_value'] = isset($node->body) ? $node->body : variable_get('weblinks_body_stub', '');
125 $form['body_field']['format'] = filter_form(isset($node->format) ? $node->format : variable_get('weblinks_format', FILTER_FORMAT_DEFAULT));
126 }
127
128 $form['url'] = array(
129 '#type' => 'textarea',
130 '#rows' => 2,
131 '#title' => t('URL'),
132 '#default_value' => isset($node->url) ? $node->url : variable_get('weblinks_url_stub', 'http://'),
133 '#required' => TRUE,
134 '#weight' => -4,
135 );
136
137 // If the weight module is available, skip this.
138 $form['node_weight'] = array(
139 '#type' => module_exists('weight') ? 'value' : 'weight',
140 '#title' => t('Weight'),
141 '#default_value' => isset($node->node_weight) ? $node->node_weight : 0,
142 '#description' => t('In listings, the heavier terms (with a larger weight) will sink and the lighter terms will be positioned nearer the top.'),
143 '#access' => user_access('administer weblinks'),
144 '#required' => TRUE,
145 );
146
147 // Validation of the url, if desired, is performed by the weblinks_checker module.
148 $form['#redirect'] = 'weblinks';
149
150 return $form;
151 }
152
153 /**
154 * Implementation of hook_access().
155 */
156 function weblinks_access($op, $node, $account) {
157 if ($op == 'create') {
158 return user_access('create weblinks', $account);
159 }
160
161 if ($op == 'update' || $op == 'delete') {
162 if (user_access('edit own weblinks', $account) && ($account->uid == $node->uid)) {
163 return TRUE;
164 }
165 if (user_access('administer weblinks', $account)) {
166 return TRUE;
167 }
168 }
169 }
170
171 /**
172 * Implementation of hook_term_path().
173 * Replaces the taxonomy term path with one for Weblinks.
174 */
175 function weblinks_term_path($term) {
176 return 'weblinks/'. $term->tid;
177 }
178
179 /**
180 * Returns the vocabulary id for weblinks navigation.
181 *
182 * @param none.
183 *
184 * @return vocid
185 * an integer specifying the vocabulary in use.
186 */
187 function _weblinks_get_vocid() {
188 $vocid = variable_get('weblinks_nav_vocabulary', '');
189 if (empty($vocid) && function_exists('taxonomy_vocabulary_load')) {
190 // Check to see if a weblinks vocabulary exists
191 $vocid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module='weblinks'"));
192 if ($vocid) {
193 // We found a vocabulary, so make sure it is associated with our content.
194 $vocabulary = (array)taxonomy_vocabulary_load($vocid);
195 $vocabulary['nodes'] = array('weblinks' => 1);
196 $status = taxonomy_save_vocabulary($vocabulary);
197 }
198 else {
199 // Didn't find one, so create vocabulary from scratch.
200 $vocabulary = array(
201 'name' => 'Web Links',
202 'multiple' => 1,
203 'required' => 0,
204 'hierarchy' => 2,
205 'relations' => 0,
206 'module' => 'weblinks',
207 'nodes' => array('weblinks' => 1),
208 );
209 $status = taxonomy_save_vocabulary($vocabulary);
210 $vocid = $vocabulary['vid'];
211 }
212 variable_set('weblinks_nav_vocabulary', $vocid);
213 }
214 return $vocid;
215 }
216
217 /**
218 * Implementation of hook_insert().
219 */
220 function weblinks_insert($node) {
221 if (!isset($node->is_converted) || !$node->is_converted) {
222 $node->last_click = NULL;
223 $node->click_count = 0;
224 }
225 weblinks_write($node);
226 }
227
228 /**
229 * Generic write function.
230 */
231 function weblinks_write($node) {
232 $node->url = strip_tags(trim($node->url));
233 $node->urlhash = md5($node->url);
234 $node->last_status = $node->last_checked = NULL;
235 if ($node->revision || $node->is_new) {
236 drupal_write_record('weblinks', $node);
237 }
238 else {
239 drupal_write_record('weblinks', $node, array('nid', 'vid'));
240 }
241 }
242
243 /**
244 * Implementation of hook_update().
245 */
246 function weblinks_update($node) {
247 if ($node->revision) {
248 $node->last_click = NULL;
249 $node->click_count = 0;
250 }
251 weblinks_write($node);
252 }
253
254 /**
255 * Implementation of hook_delete().
256 */
257 function weblinks_delete(&$node) {
258 db_query('DELETE FROM {weblinks} WHERE nid = %d', $node->nid);
259 $_REQUEST['destination'] = 'weblinks';
260 }
261
262 /**
263 * Implementation of hook_nodeapi().
264 */
265 function weblinks_nodeapi(&$node, $op, $teaser, $page) {
266 // If it's not ours, leave it alone.
267 if ($node->type != 'weblinks') {
268 return;
269 }
270 switch ($op) {
271 case 'delete revision':
272 db_query('DELETE FROM {weblinks} WHERE vid = %d', $node->vid);
273 break;
274 case 'update index':
275 // Adds URL to the search text search.
276 $text = '<h2>'. $node->url .'</h2>';
277 $parts = parse_url($node->url);
278 $pieces = explode('.', $parts['host']);
279 if (substr($pieces[0], 0, 3) == 'www') {
280 unset($pieces[0]);
281 }
282 $j = count($pieces);
283 for ($i = 0; $i < $j; ++$i) {
284 $text .= '<h2>'. implode('.', array_slice($pieces, 0, $i + 1)) .'</h2>';
285 }
286 return $text;
287 case 'presave':
288 if (!module_exists('weight')) {
289 // Non-weighted nodes have a weight of zero.
290 if (is_null($node->node_weight)) {
291 $node->node_weight = 0;
292 }
293 // Encode weight into the sticky value for the database.
294 weblinks_weight_encode($node);
295 }
296 break;
297 case 'load':
298 if (!module_exists('weight')) {
299 weblinks_weight_decode($node);
300 }
301 break;
302 }
303 }
304
305 /**
306 * Implementation of hook_load().
307 */
308 function weblinks_load($node) {
309 $obj = db_fetch_object(db_query('SELECT urlhash, url, last_status, last_checked, click_count, last_click FROM {weblinks} WHERE nid = %d AND vid=%d', $node->nid, $node->vid));
310 // This makes formatting easier.
311 $obj->none = NULL;
312 return $obj;
313 }
314
315 /**
316 * Implementation of hook_view().
317 * This formats a viewable link node.
318 */
319 function weblinks_view(&$node, $teaser = FALSE, $page = FALSE) {
320 if ($page) {
321 // Breadcrumb navigation
322 $breadcrumb = array();
323 $breadcrumb[] = l(t('Home'), '<front>');
324
325 // See the comments in hook_init.
326 $breadcrumb[] = l(_weblinks_get_menu_title(), 'weblinks');
327
328 if (isset($node->taxonomy)) {
329 $tids = array_keys($node->taxonomy);
330 $parent_links = array();
331 foreach ($tids as $tid) {
332 if ($parents = taxonomy_get_parents_all($tid)) {
333 $parents = array_reverse($parents);
334 foreach ($parents as $p) {
335 $parent_links[] = l($p->name, 'weblinks/'. $p->tid);
336 }
337 }
338 }
339 $breadcrumb[] = implode(' | ', $parent_links);
340 }
341 drupal_set_breadcrumb($breadcrumb);
342 }
343 $node->is_teaser = $teaser;
344 $node->content['body']['#value'] = theme('weblinks_link', $node, $teaser);
345 return $node;
346 }
347
348 /**
349 * Build template variables.
350 */
351 function template_preprocess_weblinks_link(&$variables) {
352 $node = $variables[0];
353 $node = node_prepare($node, $node->is_teaser);
354
355 $variables['teaser'] = $node->is_teaser;
356 // $variables['weblinks_body'] = $node->content['body']['#value'];
357
358 // Call all contribs to add to the variables.
359 $variables += module_invoke_all('weblinks_preprocess', $node);
360 }
361
362 /**
363 * Implementation of hook_weblinks_preprocess().
364 */
365 function weblinks_weblinks_preprocess($node) {
366 global $user;
367 // Making these static means we only need to set them the first time we come here.
368 static $description, $urlnode, $admin_weblinks, $edit_group, $options, $dest, $comments, $user_link;
369 if (!isset($description)) {
370 $description = variable_get('weblinks_linkdesc', TRUE);
371 $admin_weblinks = user_access('administer weblinks');
372 $edit_group = user_access('edit group weblinks');
373 $dest = drupal_get_destination();
374 $user_link = variable_get('weblinks_user_links', FALSE);
375
376 $options = array();
377 if (variable_get('weblinks_external', TRUE)) {
378 $options['attributes']['target'] = '_blank';
379 }
380
381 if (variable_get('weblinks_nofollow', FALSE)) {
382 $options['attributes']['rel'] = 'nofollow';
383 }
384 }
385 $variables = array();
386
387 $options['attributes']['title'] = check_plain($node->title);
388
389 if (variable_get('weblinks_title_link', TRUE)) {
390 $variables['title'] = l($node->title, 'node/'. $node->nid);
391 }
392 else {
393 $variables['title'] = check_plain($node->title);
394 }
395 // If this is a full-page view (e.g. node/xxx), then disregard "description" setting.
396 if (!$node->is_teaser) {
397 $description = 'body';
398 }
399 switch ($description) {
400 case 'none':
401 $variables['weblinks_body'] = NULL;
402 break;
403 case 'teaser':
404 $variables['weblinks_body'] = $node->teaser;
405 break;
406 case 'body':
407 $variables['weblinks_body'] = $node->body;
408 break;
409 }
410 $variables['link'] = theme('weblinks_node_view', $node, $options);
411
412 if (user_access('view click count')) {
413 $variables['click_count'] = $node->click_count;
414 $node->last_click = strtotime($node->last_click);
415 $variables['last_click'] = format_date($node->last_click, 'small');
416 }
417
418 return $variables;
419 }
420
421 /**
422 * Implementation of hook_link().
423 */
424 function weblinks_link($type, $object, $teaser = FALSE) {
425 global $base_path, $user;
426 static $users = array();
427 static $user_link, $admin;
428
429 $links = array();
430
431 // Make sure it's only our content and on a node page.
432 if ($type != 'node' || arg(0) == 'node') {
433 return $links;
434 }
435 if (isset($object->nid) && isset($object->type) && $object->type != 'weblinks') {
436 return $links;
437 }
438
439 // Check our static variables.
440 if (!isset($user_link)) {
441 $user_link = variable_get('weblinks_user_links', FALSE);
442 $admin = user_access('administer weblinks');
443 }
444
445 // We don't want the link if we are asking for a specific user.
446 if (arg(1) == 'user' && arg(2) == $object->uid) {
447 return $links;
448 }
449
450 if ($user_link && $object->uid != $user->uid) {
451 $links['weblinks-user-link'] = array(
452 'title' => t("!name's links", array('!name' => theme('username', $object, array('plain' => TRUE)))),
453 'href' => 'weblinks/user/'. $object->uid,
454 );
455 }
456
457 if ($admin) {
458 $dest = drupal_get_destination();
459 $links['edit'] = array(
460 'title' => t('Edit link'),
461 'href' => "node/{$object->nid}/edit",
462 'query' => $dest,
463 'attributes' => array('class' => 'weblinks-ops'),
464 );
465 $links['delete'] = array(
466 'title' => t('Delete link'),
467 'href' => "node/{$object->nid}/delete",
468 'query' => $dest,
469 'attributes' => array('class' => 'weblinks-ops'),
470 );
471 }
472
473 return $links;
474 }
475
476 function _weblinks_add() {
477 drupal_goto('node/add/weblinks');
478 }
479
480 function _weblinks_settings() {
481 drupal_goto('admin/settings/weblinks');
482 }
483
484 function _weblinks_links_page() {
485 drupal_goto('weblinks');
486 }
487
488 /**
489 * Implementation of hook_menu().
490 */
491 function weblinks_menu() {
492 $items = array();
493 // Full group listing of all weblinks categories.
494 $items['weblinks'] = array(
495 'title' => 'Web Links',
496 'page callback' => 'weblinks_page',
497 'access arguments' => array('access web links'),
498 'type' => MENU_NORMAL_ITEM,
499 ); /* */
500
501 // Main links page.
502 $items['weblinks/%'] = array(
503 'title' => 'Links page',
504 'page callback' => 'weblinks_page',
505 'page arguments' => array(1),
506 'access arguments' => array('access web links'),
507 'type' => MENU_DEFAULT_LOCAL_TASK,
508 'weight' => -5,
509 ); /* */
510
511 // Add new link.
512 $items['weblinks/add'] = array(
513 'title' => 'Add a new link',
514 'page callback' => '_weblinks_add',
515 'access arguments' => array('create weblinks'),
516 'type' => MENU_LOCAL_TASK,
517 );
518
519 // Group operations.
520 $items['weblinks/group/add'] = array(
521 'title' => 'Add a group',
522 'page callback' => '_weblinks_group_operations',
523 'page arguments' => array(2),
524 'access callback' => 'weblinks_group_access',
525 'type' => MENU_LOCAL_TASK,
526 );
527
528 $items['weblinks/group/edit'] = array(
529 'title' => 'Edit a group',
530 'page callback' => '_weblinks_group_operations',
531 'page arguments' => array(2, 3),
532 'access callback' => 'weblinks_group_access',
533 'type' => MENU_CALLBACK,
534 );
535
536 // Admin settings for the site.
537 $items['weblinks/settings'] = array(
538 'title' => 'Settings',
539 'description' => 'Set a variety of options for web link display and categorization.',
540 'page callback' => '_weblinks_settings',
541 'access arguments' => array('administer weblinks'),
542 'type' => MENU_LOCAL_TASK,
543 );
544
545 // Links redirect.
546 $items['weblinks/goto/%'] = array(
547 'title' => 'Web Links',
548 'page callback' => 'weblinks_goto',
549 'page arguments' => array(2),
550 'access arguments' => array('access web links'),
551 'type' => MENU_CALLBACK,
552 );
553
554 // User-limited links.
555 $items['weblinks/user/%'] = array(
556 'title' => 'Web Links',
557 'page callback' => '_weblinks_user',
558 'page arguments' => array(2),
559 'access arguments' => array('access web links'),
560 'type' => MENU_CALLBACK,
561 );
562
563 // User Edit weblinks
564 $items['user/%user/weblinks'] = array(
565 'title' => 'Web Links',
566 'page callback' => 'weblinks_user_page',
567 'page arguments' => array(1),
568 'file' => 'weblinks.user.inc',
569 'access arguments' => array('view my weblinks'),
570 'type' => MENU_LOCAL_TASK,
571 'weight' => 2,
572 );
573
574 // Admin settings for the site.
575 $items['admin/settings/weblinks'] = array(
576 'title' => 'Web Links',
577 'description' => 'Set a variety of options for web link display and categorization.',
578 'page callback' => 'weblinks_settings_page',
579 'file' => 'weblinks.admin.inc',
580 'access arguments' => array('administer weblinks'),
581 'type' => MENU_NORMAL_ITEM,
582 );
583
584 $items['admin/settings/weblinks/general'] = array(
585 'title' => 'General',
586 'page callback' => 'drupal_get_form',
587 'page arguments' => array('weblinks_admin_settings'),
588 'file' => 'weblinks.admin.inc',
589 'access arguments' => array('administer weblinks'),
590 'type' => MENU_DEFAULT_LOCAL_TASK,
591 'weight' => -1,
592 );
593
594 $items['admin/settings/weblinks/links'] = array(
595 'title' => 'Links page',
596 'page callback' => '_weblinks_links_page',
597 'access arguments' => array('access web links'),
598 'file' => 'weblinks.module',
599 'type' => MENU_LOCAL_TASK,
600 'weight' => 10,
601 );
602
603 return $items;
604 }
605
606 /**
607 * Determine menu access for group adding/editing.
608 */
609 function weblinks_group_access() {
610 return module_exists('taxonomy') && (user_access('administer weblinks') || user_access('edit group weblinks') || user_access('administer taxonomy'));
611 }
612
613 /**
614 * Implementation of hook_cron().
615 */
616 function weblinks_cron() {
617 global $user;
618 // Let's see if we need to refresh the random block.
619 $theme = !empty($user->theme) && !empty($themes[$user->theme]->status) ? $user->theme : variable_get('theme_default', 'garland');
620 }
621
622 /**
623 * Make a dummy term for unclassified links.
624 *
625 * @param none.
626 * @return Pseudo term object.
627 */
628 function _weblinks_unclassed() {
629 $noclass = new stdClass();
630 $noclass->tid = $noclass->vid = $noclass->depth = 0;
631 $noclass->name = variable_get('weblinks_unclassified_title', t('Unclassified'));
632 $noclass->description = $noclass->name ? variable_get('weblinks_unclassified_desc', t('These links have not been assigned a group.')) : '';
633
634 return $noclass;
635 }
636
637 /**
638 * Make a dummy term for unpublished links.
639 *
640 * @param none.
641 * @return Pseudo term object.
642 */
643 function _weblinks_unpublished() {
644 $noclass = new stdClass();
645 $noclass->vid = $noclass->depth = 0;
646 $noclass->tid = 'unpublished';
647 $noclass->name = variable_get('weblinks_unpublished_title', t('Unpublished'));
648 $noclass->description = $noclass->name ? variable_get('weblinks_unpublished_desc', t('These links are not published and need to be reviewed.')) : '';
649
650 return $noclass;
651 }
652
653 /**
654 * Format a group's fieldset.
655 *
656 * @param $term
657 * the term object being formatted.
658 * @param $tree
659 * the entire array of terms (array of objects) - will be used for handling child terms.
660 * @return
661 * The formatted HTML string.
662 */
663 function _weblinks_format_group($term, $tree) {
664 static $admin;
665 if (!isset($admin)) {
666 $admin = user_access('administer weblinks') && arg(0) != 'node';
667 }
668
669 $data = $term->image . $term->desc;
670
671 if ($admin && is_numeric($term->tid) && $term->tid !== 0) {
672 $data .= '<div class="more-link">'. l(t('Edit group'), 'weblinks/group/edit/'. $term->tid, array('query' => drupal_get_destination())) .'</div>';
673 }
674
675 $data .= _weblinks_links($term);
676 foreach ($term->children as $child) {
677 $data .= _weblinks_format_group($tree[$child], $tree);
678 }
679 // Can't be collapsed if the title is empty.
680 $fieldset = array(
681 '#title' => $term->title,
682 '#collapsible' => $term->collapsible,
683 '#collapsed' => $term->collapsed,
684 '#value' => $data,
685 );
686 return '<div class="weblinkCat weblinkCat-depth-'. $term->depth .'">'. theme('fieldset', $fieldset) ."</div>\n";
687 }
688
689 /**
690 * Returns tree of existing containers.
691 * Replacement for taxonomy_get_tree.
692 *
693 * @param $parent
694 * the parent term to restrict the tree to. (optional)
695 *
696 * @return an array of term objects.
697 */
698
699 function weblinks_get_tree($parent = 0, $quick = FALSE) {
700 $admin = user_access('administer weblinks');
701
702 $taxo_img = module_exists('taxonomy_image');
703
704 $collapsible = variable_get('weblinks_collapsible', TRUE);
705 $collapsed = variable_get('weblinks_collapsed', FALSE);
706 $empty_text = variable_get('weblinks_empty_text', NULL);
707 $skip_empty = empty($empty_text);
708 if ($admin) {
709 $skip_empty = FALSE;
710 }
711 $show_desc = variable_get('weblinks_catdesc', TRUE);
712 $format = variable_get('weblinks_format', FILTER_FORMAT_DEFAULT);
713 $max_depth = $admin ? 99999999 : variable_get('weblinks_maxfrontdepth', 1);
714
715 $tree = array();
716 if (module_exists('taxonomy')) {
717 $tree = taxonomy_get_tree(_weblinks_get_vocid(), $parent);
718 }
719
720 // Is this a top level request?
721 if ($parent) {
722 // The existing elements have depths one too low.
723 foreach ($tree as $term) {
724 ++$term->depth;
725 }
726 // Not top level, so we need to get the requested term
727 // and stick it on the front of the tree.
728 $parent_term = taxonomy_get_term($parent);
729 array_unshift($tree, $parent_term);
730 $tree[0]->depth = 0;
731 }
732 else {
733 // Top level, so do we have unclassified links?
734 $unclassed_count = db_result(_weblinks_get_query(0, 'count'));
735 if ($admin || $unclassed_count > 0) {
736 // Add our dummy unclassified term object to the list.
737 $tree[] = _weblinks_unclassed();
738 }
739
740 // Do we have unpublished nodes?
741 $unpub_count = db_result(_weblinks_get_query('unpublished', 'count'));
742 if ($admin && $unpub_count > 0) {
743 $tree[] = _weblinks_unpublished();
744 }
745 }
746
747 $new_tree = array();
748 foreach ($tree as $term) {
749 $tid = $term->tid;
750 // If we are too deep already, or the admin doesn't want it, skip the whole term.
751 $show_this_term = variable_get('weblinks_page_'. $tid, TRUE);
752 if (!$admin && ($term->depth > $max_depth || !$show_this_term)) {
753 continue;
754 }
755 // If we are suppressing empty terms and there are no links in this group, skip it.
756 if ($tid === 0) {
757 $term->node_count = $unclassed_count;
758 }
759 else {
760 if ($tid == 'unpublished') {
761 $term->node_count = $unpub_count;
762 }
763 else {
764 $term->node_count = taxonomy_term_count_nodes($tid, 'weblinks');
765 }
766 }
767 if ($skip_empty && $term->node_count == 0) {
768 continue;
769 }
770
771 $new_tree[$tid] = $term;
772 $new_tree[$tid]->children = array();
773 if ($term->parents[0] != 0) {
774 foreach ($term->parents as $parent) {
775 if (isset($new_tree[$parent])) {
776 $new_tree[$parent]->children[] = $tid;
777 }
778 }
779 }
780
781 $new_tree[$tid]->limit = variable_get('weblinks_maxdisp_'. $tid, '');
782 $new_tree[$tid]->sort = variable_get('weblinks_group_sort_'. $term->tid, '');
783
784 // Collapsible is more complicated than just the setting.
785 $new_tree[$tid]->collapsible = $collapsible && ($new_tree[$tid]->depth < $max_depth) && !empty($term->name);
786 $collapse_me = variable_get('weblinks_collapse_'. $tid, FALSE);
787 $new_tree[$tid]->collapsed = $collapsed || ($new_tree[$tid]->depth > $max_depth) || ($new_tree[$tid]->collapsible ? $collapse_me : FALSE);
788
789 if ($new_tree[$tid]->collapsible) {
790 $new_tree[$tid]->title = check_plain($term->name);
791 }
792 else {
793 if (variable_get('weblinks_linktitle', TRUE)) {
794 $new_tree[$tid]->title = l($term->name, 'weblinks/'. $tid);
795 }
796 else {
797 $new_tree[$tid]->title = check_plain($term->name);
798 }
799 }
800
801 $new_tree[$tid]->desc = NULL;
802 if ($show_desc && $new_tree[$tid]->collapsible) {
803 if ($term->description) {
804 $new_tree[$tid]->desc = '<div class="weblinks-cat-desc">'. check_markup($term->description, $format, FALSE) .'</div><!--class="weblinks-cat-desc"-->';
805 }
806 }
807 else {
808 $new_tree[$tid]->desc = '';
809 }
810 // Position first node after whatever description there was.
811 $new_tree[$tid]->desc .= '<div class="clear-block"></div>';
812 $new_tree[$tid]->image = $taxo_img ? '<div class="weblinks-cat-image">'. taxonomy_image_display($term->tid, NULL, NULL, array('wrapper' => FALSE)) .'</div>' : NULL;
813 }
814 return $new_tree;
815 }
816
817 /**
818 * Display the main web links page, separated by category (term).
819 *
820 * @param $tid
821 * The term for which to display the links. If ommitted or 0, then show all.
822 *
823 * @return
824 * HTML formatted page.
825 */
826 function weblinks_page($tid = 0) {
827 global $base_path;
828
829 // Get the page description, if there is one
830 // $output = theme('weblinks_pagedesc');
831
832 // If the tid is not numeric, we came from a block "more".
833 if (!is_numeric($tid)) {
834 if (!in_array($tid, array('popular', 'recent', 'unpublished', 'random')) || !module_exists('weblinks_blocks')) {
835 drupal_set_message(t('Invalid group requested (%tid).', array('%tid' => $tid)), 'error');
836 return ' ';
837 }
838
839 $group_id = arg(2);
840 $content = _weblinks_blocks_content($tid, $tid, 0, $group_id);
841
842 $term = taxonomy_get_term($group_id);
843 $fieldset = array(
844 '#title' => check_plain(drupal_ucfirst($tid) .' '. $term->name),
845 '#collapsible' => variable_get('weblinks_collapsible', TRUE),
846 '#collapsed' => FALSE,
847 '#value' => $content,
848 );
849 $output = '<div class="weblinkCat weblinkCat-depth-0">'. theme('fieldset', $fieldset) ."</div>\n";
850 return $output;
851 }
852
853 $tree = weblinks_get_tree($tid);
854 foreach ($tree as $term) {
855 if ($term->depth == 0) {
856 $output .= _weblinks_format_group($term, $tree);
857 }
858 }
859
860 if (!$output) {
861 $output .= '<p>'. t('There are no weblinks to display yet.') .'</p>';
862 }
863
864 return $output;
865 }
866
867 /**
868 * Handle group operations.
869 */
870 function _weblinks_group_operations($op, $tid = NULL) {
871 if (!weblinks_group_access()) {
872 drupal_access_denied();
873 }
874
875 // Force admin theme.
876 global $custom_theme;
877 $custom_theme = variable_get('admin_theme', '0');
878 drupal_add_css(drupal_get_path('module', 'system') .'/admin.css');
879 drupal_add_css(drupal_get_path('module', 'weblinks') .'/weblinks.admin.css');
880
881 drupal_set_title(t('Group !op', array('!op' => $op)));
882
883 include_once(drupal_get_path('module', 'taxonomy') .'/taxonomy.admin.inc');
884
885 $vocabulary = taxonomy_vocabulary_load(_weblinks_get_vocid());
886 $_REQUEST['destination'] = 'weblinks';
887
888 switch ($op) {
889 case 'add':
890 return drupal_get_form('taxonomy_form_term' , $vocabulary);
891
892 case 'edit':
893 return taxonomy_admin_term_edit($tid);
894 }
895 }
896
897 /**
898 * Process page for specific user.
899 *
900 * @param $uid
901 * user id to retrieve.
902 *
903 * @return the page of links submitted by the user.
904 */
905 function _weblinks_user($uid) {
906 $output = $username = NULL;
907 $linkdesc = variable_get('weblinks_linkdesc', 'teaser');
908
909 // See if name instead of id.
910 if (!is_numeric($uid)) {
911 $uid = _weblinks_find_user($uid);
912 }
913
914 $result = _weblinks_get_query($uid, 'user', 0);
915 while ($row = db_fetch_object($result)) {
916 $node = node_load($row->nid);
917 if (!$username) {
918 $username = theme('username', $node);
919 }
920 $output .= node_view($node, !($linkdesc == 'body'));
921 }
922 drupal_set_title(t('Links submitted by !name', array('!name' => $username)));
923 $breadcrumb = drupal_get_breadcrumb();
924 $breadcrumb[] = l(_weblinks_get_menu_title(), 'weblinks');
925 drupal_set_breadcrumb($breadcrumb);
926 return $output;
927 }
928
929 function _weblinks_find_user($name) {
930 if (function_exists('user_locate')) {
931 $account = user_locate(array('name' => $name));
932 $uid = $account->uid;
933 }
934 else {
935 $uid = db_result(db_query("SELECT uid FROM {users} WHERE name='%s'", $name));
936 }
937 return $uid;
938 }
939
940 /**
941 * Process redirect for URL. Count clicks and node views.
942 *
943 * @param $nid
944 * node id that contains the link.
945 * $param $update_node_counter
946 * bool indicating whether or not the node view counter should be updated.
947 *
948 * @return none.
949 * the page will be redirected (302) to the desired URL.
950 */
951 function weblinks_goto($nid) {
952 $node = db_fetch_object(db_query("SELECT n.nid, n.vid, l.url FROM {node} n LEFT JOIN {weblinks} l USING(nid, vid) WHERE n.nid=%d", $nid));
953 $qargs = array(date('Y-m-d H:i:s'), $nid, $node->vid);
954 db_query("UPDATE {weblinks} SET click_count=click_count+1, last_click='%s' WHERE nid=%d AND vid=%d", $qargs);
955 if (module_exists('statistics')) {
956 statistics_exit('node', $nid, '');
957 }
958 header('Location: '. $node->url);
959 }
960
961 /**
962 * Prepare links content.
963 *
964 * @param $term
965 * a term object to process links for.
966 *
967 * @return
968 * list of links for the given term (HTML).
969 */
970 function _weblinks_links($term) {
971 global $user;
972 // Making these static means we only need to set them the first time we come here.
973 static $options, $empty_text, $filter_format, $linkdesc;
974 if (!isset($empty_text)) {
975 $empty_text = variable_get('weblinks_empty_text', NULL);
976 $filter_format = variable_get('weblinks_format', FILTER_FORMAT_DEFAULT);
977 $linkdesc = variable_get('weblinks_linkdesc', 'teaser');
978
979 $options = array();
980 if (variable_get('weblinks_external', TRUE)) {
981 $options['attributes']['target'] = '_blank';
982 }
983
984 if (variable_get('weblinks_nofollow', FALSE)) {
985 $options['attributes']['rel'] = 'nofollow';
986 }
987 }
988
989 $output = NULL;
990
991 $limit = isset($term->limit) ? $term->limit : 99999999;
992 $need_more = $limit < $term->node_count;
993
994 if ($term->tid === 'unpublished') {
995 $sort_order = 'recent';
996 }
997 else {
998 $sort_order = variable_get('weblinks_group_sort_'. $term->tid, variable_get('weblinks_page_sort', 'title'));
999 }
1000
1001 $result = _weblinks_get_query($term->tid, $sort_order, ($limit ? ++$limit : 0));
1002
1003 $items = array();
1004 $i = 0;
1005 while ($row = db_fetch_array($result)) {
1006 $node = node_load($row['nid']);
1007 $output .= node_view($node, !($linkdesc == 'body'), FALSE, TRUE);
1008 }
1009
1010 // Do we need a "more" link?
1011 if ($need_more) {
1012 $more_link = '<div class="more-link">'. l(t('more&#8230;'), 'weblinks/'. $term->tid) .'</div>';
1013 }
1014 else {
1015 $more_link = NULL;
1016 }
1017 if ($term->node_count == 0) {
1018 $output = check_markup($empty_text, $filter_format, FALSE);
1019 }
1020
1021 return decode_entities($output);
1022 }
1023
1024 /**
1025 * Trim the link title (either text or the url itself) to the admin-specified length.
1026 */
1027 function _weblinks_trim($text, $length = NULL) {
1028 if (!$length) {
1029 // Blocks have to specify the length.
1030 $length = variable_get('weblinks_trim', 0);
1031 }
1032
1033 // Zero means no limit;
1034 if ($length == 0) {
1035 return $text;
1036 }
1037
1038 // Use +3 for '...' string length.
1039 if (drupal_strlen($text) > $length + 3) {
1040 $text = drupal_substr($text, 0, $length) .'...';
1041 }
1042
1043 return $text;
1044 }
1045
1046 /**
1047 * General database query function.
1048 *
1049 * @param $tid
1050 * the term id to fetch links for. May be a comma separated list.
1051 * @param $sort
1052 * the order in which to sort.
1053 * @param $limit
1054 * the maximum number of rows to retrieve - 0 means unlimited.
1055 *
1056 * @return result set from the query.
1057 */
1058 function _weblinks_get_query($tid = 0, $sort = 'title', $limit = 0) {
1059 if ($tid === 'unpublished') {
1060 $where = 'WHERE n.status = 0 ';
1061 }
1062 else {
1063 $where = 'WHERE n.status = 1 ';
1064 }
1065
1066 $join = 'INNER JOIN {weblinks} bw ON n.vid = bw.vid '; // acts as filter on {node}
1067 // In some cases we need a join on term_node; in some we don't. We decide later according to $sort
1068 if (function_exists('taxonomy_get_term')) {
1069 if ($tid == 0) {
1070 $join_tn = 'LEFT JOIN {term_node} tn ON tn.nid=n.nid AND tn.vid=n.vid ';
1071 $where_tn = 'AND tn.nid IS NULL ';
1072 }
1073 else {
1074 $join_tn = 'INNER JOIN {term_node} tn ON tn.nid=n.nid AND tn.vid=n.vid ';
1075 $where_tn = 'AND tn.tid IN (%s) ';
1076 }
1077 }
1078 else {
1079 $join_tn = '';
1080 $where_tn = '';
1081 }
1082
1083 switch ($sort) {
1084 case 'standard':
1085 $cols = 'n.nid, n.sticky, n.created';
1086 $join .= $join_tn;
1087 $where .= $where_tn;
1088 $order = 'ORDER BY n.sticky DESC, n.created ASC';
1089 break;
1090 case 'title':
1091 $cols = 'n.nid, n.title';
1092 $join .= $join_tn;
1093 $where .= $where_tn;
1094 $order .= 'ORDER BY n.sticky DESC, n.title ASC';
1095 break;
1096 case 'popular':
1097 $cols = 'n.nid, bw.click_count, bw.last_click';
1098 $where .= 'AND bw.click_count>0 ';
1099 $order .= 'ORDER BY bw.click_count DESC, bw.last_click DESC';
1100 break;
1101 case 'user':
1102 $cols = 'n.nid, n.sticky, n.created';
1103 $where .= 'AND n.uid=%s ';
1104 $order .= 'ORDER BY n.sticky, n.created';
1105 break;
1106 case 'recent':
1107 $cols = 'n.nid, n.changed, n.title';
1108 if ($tid != 0) {
1109 $join .= $join_tn;
1110 $where .= $where_tn;
1111 }
1112 $order .= 'ORDER BY n.changed DESC, n.title ASC';
1113 break;
1114 case 'random':
1115 $cols = 'n.nid';
1116 if ($tid != 0) {
1117 $join .= $join_tn;
1118 $where .= $where_tn;
1119 }
1120 $order .= 'ORDER BY RAND()';
1121 break;
1122 case 'count':
1123 $cols = 'COUNT(n.nid)';
1124 if ($tid !== 'unpublished') {
1125 $join .= $join_tn;
1126 $where .= $where_tn;
1127 }
1128 $order = '';
1129 break;
1130 }
1131
1132 $query = 'SELECT ' . $cols . ' FROM {node} n ' . $join . $where . $order;
1133 $query = db_rewrite_sql($query);
1134 // drupal_set_message("$tid, $sort: ".$query);
1135
1136 if ($limit) {
1137 $result = db_query_range($query, $tid, 0, $limit);
1138 }
1139 else {
1140 $result = db_query($query, $tid);
1141 }
1142
1143 return $result;
1144 }
1145
1146 /**
1147 * Implementation of hook_form_alter
1148 * Alters the taxonomy term form to allow us to use it.
1149 * @TODO - check if necessary for this user and include. ** if (weblinks_group_access()) { **
1150 */
1151 function weblinks_form_alter(&$form, &$form_state, $form_id) {
1152 switch ($form_id) {
1153 case 'taxonomy_form_term':
1154 // Is this for our vocabulary?
1155 if ($form['#vocabulary']['vid'] != _weblinks_get_vocid()) {
1156 return '';
1157 }
1158 $form['identification']['#weight'] = -10;
1159 $form['identification']['#collapsible'] = FALSE;
1160 $form['identification']['name']['#title'] = t('Group name');
1161 $form['identification']['name']['#description'] = t('The name of this group.');
1162 $form['identification']['description']['#title'] = t('Group description');
1163 $form['identification']['description']['#description'] = t('A description of the group, to be displayed on web links pages and forms.');
1164
1165 $form['advanced']['#weight'] = -5;
1166 $form['advanced']['parent']['#description'] = t('Parent groups.');
1167 $form['advanced']['weight']['#description'] = t('Groups are displayed in ascending order by weight.');
1168 unset($form['advanced']['relations']);
1169