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

Contents of /contributions/modules/taxonomy_quick_find/taxonomy_quick_find.module

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


Revision 1.4 - (show annotations) (download) (as text)
Wed Sep 17 22:52:17 2008 UTC (14 months, 1 week ago) by njt1982
Branch: MAIN
CVS Tags: DRUPAL-6--1-0, HEAD
Branch point for: DRUPAL-6--1
Changes since 1.3: +383 -142 lines
File MIME type: text/x-php
Syncing HEAD to a drupal 6 compatible release ready for branching
1 <?php
2 // $Id: taxonomy_quick_find.module,v 1.3.2.10 2008/09/17 15:43:50 njt1982 Exp $
3
4 /**
5 * @file
6 * This module provides customizable blocks which pickup the terms for the current node and allow a visitor to browse other content by similar nodes
7 */
8
9
10 /**
11 * Implementation of hook_help().
12 */
13 function taxonomy_quick_find_help($path, $arg) {
14 switch ($path) {
15 case 'admin/settings/taxonomy_quick_find' :
16 return t('Configure the blocks provided by this module here. You can add new blocks or remove existing ones from here too. Each block can be configured to provide suggestions for specific content types.');
17 }
18 }
19
20
21 /**
22 * Implementation of hook_menu().
23 */
24 function taxonomy_quick_find_menu() {
25 $items = array();
26
27 $items['admin/settings/taxonomy_quick_find'] = array(
28 'title' => 'Taxonomy Quick Find',
29 'description' => 'Configure provided blocks',
30 'page callback' => 'taxonomy_quick_find_admin',
31 'access callback' => 'user_access',
32 'access arguments' => array('administer taxonomy'),
33 );
34
35 $items['taxonomy_quick_find'] = array(
36 'page callback' => 'taxonomy_quick_find_json',
37 'access callback' => 'user_access',
38 'access arguments' => array('access content'),
39 'type' => MENU_CALLBACK,
40 );
41
42 return $items;
43 }
44
45
46 function taxonomy_quick_find_theme($existing, $type, $theme, $path) {
47 return array(
48 'taxonomy_quick_find_admin_configure_block_node_types' => array(
49 'arguments' => array('form' => NULL),
50 )
51 );
52 }
53
54
55
56 /**
57 * Administation page. Provides a list of existing blocks along with a form to add new ones.
58 *
59 * @param string $op
60 * The operation being performed. Default to 'list', but can be 'delete'.
61 *
62 * @param string $delta
63 * Only used when $op = 'delete. Defines which block is being deleted.
64 *
65 * @return string
66 * Rendered Output
67 */
68 function taxonomy_quick_find_admin($op = 'list', $delta = NULL) {
69 $v = taxonomy_get_vocabularies();
70 if (count($v) == 0) {
71 drupal_set_message(t('You must have created at least 1 vocabulary'), 'error');
72 return '';
73 }
74
75
76 $blocks = variable_get('taxonomy_quick_find_blocks', array());
77
78 if ($op == 'delete') {
79 if (!is_numeric($delta) || !isset($blocks[$delta])) {
80 return drupal_not_found();
81 }
82 return drupal_get_form('taxonomy_quick_find_admin_confirm_delete', $delta);
83 }
84
85 $nodetypes = node_get_types('names');
86
87 $rows = array();
88 foreach ($blocks as $delta => $block) {
89 if (empty($block['types'])) {
90 $blocktypes = array('<em>'. t('None Set') .'</em>');
91 }
92 else {
93 $blocktypes = array_keys($block['types']);
94 array_walk($blocktypes, '_taxonomy_quick_find_walk_node_types', array('nodetypes' => node_get_types('names'), 'block' => $block['types']));
95 }
96
97 $row = array();
98 $row[] = $block['name'];
99 $row[] = theme('item_list', $blocktypes);
100
101 $ops = l(t('edit'), 'admin/build/block/configure/taxonomy_quick_find/'. $delta, array('query' => 'destination=admin/settings/taxonomy_quick_find'));
102 $ops .= ' | ';
103 $ops .= l(t('delete'), 'admin/settings/taxonomy_quick_find/delete/'. $delta);
104 $row[] = $ops;
105
106 $rows[] = $row;
107 }
108
109 $output = theme('table', array(t('Title'), t('Configured Types'), t('Ops')), $rows);
110
111 $output .= drupal_get_form('taxonomy_quick_find_admin_configure_block', NULL);
112 return $output;
113 }
114
115
116 /**
117 * Block delete confirmation form
118 *
119 * @param string $delta
120 * The delta of the block being deleted
121 *
122 * @return array
123 * FAPI structured array
124 */
125 function taxonomy_quick_find_admin_confirm_delete(&$form_state, $delta) {
126 $form = array();
127 $form['delta'] = array(
128 '#type' => 'hidden',
129 '#value' => $delta
130 );
131
132 return confirm_form(
133 $form,
134 t('Are you sure you want to delete this block?'),
135 'admin/settings/taxonomy_quick_find',
136 t('Note: This action cannt be undone'),
137 t('Delete'),
138 t('Cancel')
139 );
140 }
141
142
143 /**
144 * Submit handler for 'taxonomy_quick_find_admin_confirm_delete' form.
145 */
146 function taxonomy_quick_find_admin_confirm_delete_submit($form, &$form_state) {
147 $blocks = variable_get('taxonomy_quick_find_blocks', array());
148
149 drupal_set_message(t('Deleted Block: %name', array('%name' => $blocks[ $form_state['values']['delta'] ]['name'])));
150
151 unset($blocks[ $form_state['values']['delta'] ]);
152
153 variable_set('taxonomy_quick_find_blocks', $blocks);
154
155 $form_state['redirect'] = 'admin/settings/taxonomy_quick_find';
156 return;
157 }
158
159
160 /**
161 * Block configuration/creation form
162 *
163 * @param string $delta
164 * Delta of the block being configured. If NULL, then block is being created.
165 *
166 * @return array
167 * FAPI structured array
168 */
169 function taxonomy_quick_find_admin_configure_block(&$form_state, $delta = NULL) {
170 if (isset($delta)) {
171 $settings = _taxonomy_quick_find_get_block($delta);
172 }
173 $settings = is_array($settings) ? $settings : array();
174
175 $form = array();
176 $form['tqf'] = array(
177 '#type' => 'fieldset',
178 '#title' => isset($delta) ? t('Block Settings') : t('Add Block'),
179 '#tree' => TRUE,
180 '#collapsible' => TRUE,
181 '#collapsed' => !isset($delta),
182 );
183
184 //The Block Name
185 $form['tqf']['name'] = array(
186 '#title' => t('Block Name'),
187 '#type' => 'textfield',
188 '#required' => TRUE,
189 '#description' => t('Human readable name for this block. This is for reference and <strong>wont</strong> be used as the block\'s title.'),
190 '#default_value' => isset($settings['name']) ? $settings['name'] : '',
191 );
192
193
194 //The Node Types container
195 $form['tqf']['types'] = array(
196 '#type' => 'item',
197 '#theme' => 'taxonomy_quick_find_admin_configure_block_node_types',
198 '#description' => 'A limit of zero for a node type will disable the node type. Use the weight to control the position of the node type in the block.',
199 '#title' => t('Node Types')
200 );
201
202 //create a form element for each node type consisting of a 'label' element, a limit textifield and a weight select box
203 foreach (node_get_types('names') as $id => $name) {
204 $form['tqf']['types'][$id]['label'] = array('#type' => 'markup', '#value' => check_plain($name));
205
206 $form['tqf']['types'][$id]['limit'] = array(
207 '#type' => 'textfield',
208 '#default_value' => isset($settings['types'][$id]['limit']) ? $settings['types'][$id]['limit'] : 0,
209 '#max_length' => 3,
210 '#size' => 2,
211 );
212
213 $form['tqf']['types'][$id]['weight'] = array(
214 '#type' => 'weight',
215 '#default_value' => isset($settings['types'][$id]['weight']) ? $settings['types'][$id]['weight'] : 0,
216 );
217 }
218
219
220 //Define the checkboxes array for the vocabulary configuration
221 $vocabs = array();
222 foreach (taxonomy_get_vocabularies() as $v) {
223 $vocabs[$v->vid] = $v->name;
224 }
225
226 $form['tqf']['vocabs'] = array(
227 '#title' => t('Vocabularies'),
228 '#type' => 'checkboxes',
229 '#description' => t('Check the vocabularies you would like the terms limited to.'),
230 '#options' => $vocabs,
231 '#default_value' => isset($settings['vocabs']) ? $settings['vocabs'] : array_keys($vocabs),
232 );
233
234
235 //If there is a delta then we are editing on a block configuration, otherwise we are adding
236 if (isset($delta)) {
237 $form['tqf']['#validate']['_taxonomy_quick_find_block_configure_configure_block_validate'] = array();
238 }
239 else {
240 $form['tqf']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
241 }
242
243 //We need a CSS file to control some layout features.
244 drupal_add_css(drupal_get_path('module', 'taxonomy_quick_find') .'/taxonomy_quick_find.css');
245 return $form;
246 }
247
248
249 /**
250 * Theme function for the node type container element of the above form.
251 */
252 function theme_taxonomy_quick_find_admin_configure_block_node_types($form) {
253 $rows = array();
254 foreach (element_children($form) as $key) {
255 $row = array();
256 $row[] = drupal_render($form[$key]['label']);
257 $row[] = drupal_render($form[$key]['limit']);
258 $row[] = drupal_render($form[$key]['weight']);
259 $rows[] = $row;
260 }
261
262 return theme(
263 'table',
264 array(t('Type'), t('Limit'), t('Weight')),
265 $rows,
266 array('id' => 'block_tqf_nodetypes')
267 );
268 }
269
270
271 /**
272 * Validate callback function for the above form. This is only used for EXISTING blocks which are being edited.
273 */
274 function _taxonomy_quick_find_block_configure_configure_block_validate($form, $form_id = NULL) {
275 $form_values = array();
276
277 foreach (element_children($form) as $key) {
278 switch ($key) {
279 case 'types' :
280 foreach (element_children($form['types']) as $typekey) {
281 $form_values['tqf']['types'][$typekey] = array(
282 'limit' => $form['types'][$typekey]['limit']['#value'],
283 'weight' => $form['types'][$typekey]['weight']['#value'],
284 );
285 }
286 break;
287
288 default :
289 $form_values['tqf'][$key] = $form[$key]['#value'];
290 break;
291 }
292 }
293
294 taxonomy_quick_find_admin_configure_block_validate(NULL, $form_values);
295 }
296
297
298 /**
299 * Validate hook for the add block form (plus the edit block after the above function has rebuilt some form_values).
300 */
301 function taxonomy_quick_find_admin_configure_block_validate($form, &$form_state) {
302 foreach ($form_state['values']['tqf']['types'] as $id => $v) {
303 if (!is_numeric($v['limit']) || $v['limit'] < 0) {
304 form_set_error('tqf][types]['. $id .'][limit', t('The limit for %field must be a positive integer or zero to disable.', array('%field' => $id)));
305 }
306 }
307
308 //Check there is at least one vocabulary selected
309 $form_state['values']['tqf']['vocabs'] = array_filter($form_state['values']['tqf']['vocabs']);
310 if (empty($form_state['values']['tqf']['vocabs'])) {
311 form_set_error('tqf][vocabs', t('You must select at least one vocabulary'));
312 }
313 }
314
315
316 /**
317 * Submit handler for block configuration/addition form
318 */
319 function taxonomy_quick_find_admin_configure_block_submit($form, &$form_state) {
320 $blocks = variable_get('taxonomy_quick_find_blocks', array());
321
322 foreach ($form_state['values']['tqf']['types'] as $type => $settings) {
323 if ($settings['limit'] == 0) {
324 unset($form_state['values']['tqf']['types'][$type]);
325 }
326 else {
327 $form_state['values']['tqf']['types'][$type]['limit'] = (int)$form_state['values']['tqf']['types'][$type]['limit'] ;
328 }
329 }
330
331 //Sort the types (if its an array AND the array contains more than 1 type).
332 if (is_array($form_state['values']['tqf']['types']) && count($form_state['values']['tqf']['types']) > 1) {
333 uasort($form_state['values']['tqf']['types'], '_taxonomy_quick_find_type_sort');
334 }
335
336 //Filter the disabled vocabs out of the array - no need to store them!
337 $form_state['values']['tqf']['vocabs'] = array_filter($form_state['values']['tqf']['vocabs']);
338
339 //If delta is set, save over the old block data...
340 if (isset($form_state['values']['delta'])) {
341 $blocks[ $form_state['values']['delta'] ] = array(
342 'name' => $form_state['values']['tqf']['name'],
343 'types' => $form_state['values']['tqf']['types'],
344 'vocabs' => $form_state['values']['tqf']['vocabs'],
345 );
346 }
347 //otherwise add a new block entry
348 else {
349 $blocks[] = array(
350 'name' => $form_state['values']['tqf']['name'],
351 'types' => $form_state['values']['tqf']['types'],
352 'vocabs' => $form_state['values']['tqf']['vocabs'],
353 );
354 }
355
356 variable_set('taxonomy_quick_find_blocks', $blocks);
357 }
358
359
360 /**
361 * Implementation of hook_block().
362 */
363 function taxonomy_quick_find_block($op = 'list', $delta = 0, $edit = array()) {
364 switch ($op) {
365 case 'list' :
366 $configured_blocks = variable_get('taxonomy_quick_find_blocks', array());
367 $blocks = array();
368 foreach ($configured_blocks as $delta => $settings) {
369 $blocks[$delta] = array('info' => t('TQF') .':'. $settings['name']);
370 }
371
372 return $blocks;
373
374 case 'configure' :
375 return taxonomy_quick_find_admin_configure_block($form_state, $delta);
376
377 case 'save' :
378 $edit = array('values' => $edit);
379 taxonomy_quick_find_admin_configure_block_submit(NULL, $edit);
380 break;
381
382 case 'view' :
383 if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == '') {
384 return array('content' => taxonomy_quick_find_view_block($delta));
385 }
386 break;
387
388 }
389 }
390
391 /**
392 * Helper function to get the settings for a block defined by its Delta
393 *
394 * @param string $delta
395 * Delta identification of block
396 *
397 * @return array
398 * Array of settings
399 */
400 function _taxonomy_quick_find_get_block($delta) {
401 $settings = variable_get('taxonomy_quick_find_blocks', array());
402 return isset($settings[$delta]) ? $settings[$delta] : FALSE;
403 }
404
405
406 /**
407 * Function to get the contents for a block. This also includes the Javascript too.
408 *
409 * @param string $delta
410 * Delta identification of block to be displayed
411 *
412 * @return string
413 * Rendered Output
414 */
415 function taxonomy_quick_find_view_block($delta) {
416 if ($block = _taxonomy_quick_find_get_block($delta)) {
417 //Get the terms for this node
418 $terms = taxonomy_node_get_terms(menu_get_object());
419
420 //If there are no terms for the node at all then there isn't a lot of point continuing...
421 if (empty($terms)) {
422 return FALSE;
423 }
424
425 //Remove all terms which aren't part of the blocks "vocab" list
426 if (!empty($block['vocabs']) && is_array($block['vocabs'])) {
427 foreach ($terms as $tid => $term) {
428 if (!$block['vocabs'][ $term->vid ]) {
429 unset($terms[$tid]);
430 }
431 }
432 }
433
434 //One last check to see if the terms array is empty (after removing ones from excluded vocabs)...
435 if (empty($terms)) {
436 return FALSE;
437 }
438
439 //TODO: Find nice way to preselect a term - maybe based on where the user came from (eg, taxonomy/term/12, preselect TID:12?)
440 reset($terms);
441 $term = current($terms);
442 $preset = $term->tid;
443
444
445 //By this point there should be at least ONE term in the array,
446 // If there is more than 1 term, add the "select a term" AJAX menu...
447 // If there is ONLY 1 term, use a static link.
448 if (count($terms) > 1) {
449 //Create form - preselecting a node, if necessary...
450 drupal_add_js(drupal_get_path('module', 'taxonomy_quick_find') .'/taxonomy_quick_find.js');
451 drupal_add_css(drupal_get_path('module', 'taxonomy_quick_find') .'/taxonomy_quick_find.css');
452 $output = drupal_get_form('taxonomy_quick_find_block_form', $delta, $terms, $preset);
453 }
454 else {
455 reset($terms);
456 $output = theme('taxonomy_quick_find_one_term', current($terms));
457 }
458
459 $types = node_get_types('names');
460 //Render out nodes for the types...
461 foreach ($block['types'] as $type => $settings) {
462 //If the limit is, somehow, not more than 0 - use a default of '3'.
463 if (!($setting['limit'] > 0)) {
464 $setting['limit'] = 3;
465 }
466
467 $result = db_query('SELECT n.nid, n.title FROM {node} n INNER JOIN {term_node} tn USING (nid) WHERE n.type = "%s" AND n.status = 1 AND tn.tid = %d ORDER BY n.created DESC LIMIT %d', $type, $preset, $settings['limit']);
468
469 $items = array();
470 while ($node = db_fetch_object($result)) {
471 $items[] = l($node->title, 'node/'. $node->nid);
472 }
473
474 if (empty($items)) {
475 $output .= theme('item_list', array(t('No items found.')), ucwords(t($type)), 'ul', array('class' => 'tqf_'. $type));
476 }
477 else {
478 $output .= theme('item_list', $items, ucwords(t($types[$type])), 'ul', array('class' => 'tqf_'. $type));
479 }
480 }
481 return $output;
482 }
483 else {
484 return '';
485 }
486 }
487
488
489 /**
490 * Form for the block. This provides a drop down menu of all the terms for the current node.
491 *
492 * @param string $delta
493 * Block Delta
494 *
495 * @param array $terms
496 * Array of term objects, usually provided by taxonomy_node_get_terms
497 *
498 * @param int $preset
499 * (Optional) Term ID for preselected term in the drop down.
500 *
501 * @return array
502 * FAPI structured array
503 */
504 function taxonomy_quick_find_block_form($form_state = NULL, $delta, $terms, $preset = NULL) {
505 $form = array();
506
507 foreach ($terms as $tid => $term) {
508 $terms[$tid] = $term->name;
509 }
510
511 $form['terms'] = array(
512 '#type' => 'select',
513 '#options' => $terms,
514 '#title' => t('Select a term'),
515 '#attributes' => array('onchange' => 'Drupal.taxonomyQuickFind('. $delta .', this);'),
516 '#default_value' => $preset,
517 );
518
519 return $form;
520 }
521
522
523 /**
524 * JSON Callback. Provides the nodes for the newly selected terms.
525 *
526 * @param string $delta
527 * Block Delta. Required so we know which node types to limit the block to
528 *
529 * @param int $tid
530 * Selected Term ID
531 */
532 function taxonomy_quick_find_json($delta = NULL, $tid = NULL) {
533
534 if (is_null($delta) || is_null($tid)) {
535 drupal_not_found();
536 exit;
537 }
538
539 if (isset($delta) && $block = _taxonomy_quick_find_get_block($delta)) {
540 $items = array();
541 foreach ($block['types'] as $type => $settings) {
542 //If the limit is, somehow, not more than 0 - use a default of '3'.
543 if (!($setting['limit'] > 0)) {
544 $setting['limit'] = 3;
545 }
546
547 $result = db_query('SELECT n.nid FROM {node} n INNER JOIN {term_node} tn USING (nid) WHERE n.type = "%s" AND n.status = 1 AND tn.tid = %d ORDER BY n.created DESC LIMIT %d', $type, $tid, $settings['limit']);
548
549 while ($nid = db_fetch_array($result)) {
550 $node = node_load($nid['nid']);
551 $items[$type][] = array('title' => $node->title, 'url' => url('node/'. $node->nid));
552 }
553
554 if (empty($items[$type])) {
555 $items[$type][] = array('title' => t('No items found.'));
556 }
557 }
558
559
560 drupal_set_header('Content-Type: text/javascript; charset=utf-8');
561 print drupal_to_js($items);
562 ob_start();
563 module_invoke_all('exit');
564 ob_end_clean();
565 exit;
566
567 }
568 else {
569 drupal_access_denied();
570 exit;
571 }
572 }
573
574
575 /**
576 * Theme function to allow overriding of the "one term" header for nodes with only one term accessible
577 *
578 * @param object $term
579 * Term Object from Taxonomy_get_term
580 *
581 * @return string
582 */
583 function theme_taxonomy_quick_find_one_term($term) {
584 return t('Items for !term', array('!term' => l($term->name, taxonomy_term_path($term))));
585 }
586
587
588 /**
589 * Private function for sorting vocabularies
590 */
591 function _taxonomy_quick_find_type_sort($a, $b) {
592 if ($a['weight'] > $b['weight']) {
593 return 1;
594 }
595 elseif ($a['weight'] < $b['weight']) {
596 return-1;
597 }
598
599 // TODO: This isn't ideal - what to do if the weights are the same?! We dont know the name of the block here so cant do alphabetical..
600 return 0;
601 }
602
603
604 function _taxonomy_quick_find_walk_node_types(&$item, $key, $data) {
605 $item = t('%type (!count node limit)', array(
606 '%type' => isset($data['nodetypes'][$item]) ? $data['nodetypes'][$item] : t('Unknown Node Type'),
607 '!count' => $data['block'][$item]['limit'],
608 ));
609 }

  ViewVC Help
Powered by ViewVC 1.1.2