/[drupal]/contributions/sandbox/jjeff/prevnext/prevnext.module
ViewVC logotype

Contents of /contributions/sandbox/jjeff/prevnext/prevnext.module

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


Revision 1.2 - (show annotations) (download) (as text)
Fri Sep 8 22:28:50 2006 UTC (3 years, 2 months ago) by jjeff
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +136 -36 lines
File MIME type: text/x-php
Pretty close to working... Needs LOTs of cleanup and rearranging.
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * Adds blocks with several types of previous/next links for nodes
7 *
8 * @todo
9 * - remove assumptions that order of nids == order of nodes (order by sticky DESC, created DESC)
10 * - abstract things so that you can have as many prevnext blocks of as many types as you want
11 * example: several blocks for several terms, views, etc...
12 * - support heirarchichal vocabularies
13 * - add support for "first" and "last"
14 * - create separate textareas for first, previous, next, and last... as well as a textfield for the delimiter
15 * - have block names reflect the configuration. example: "Prev/Next within "about" category
16 *
17 * wayyyy down the road:
18 * - X number of previous
19 * - X number of next
20 *
21 */
22
23 /**
24 * Implementation of hook_block().
25 */
26 function prevnext_block($op = 'list', $delta = 0, $edit = array()) {
27 if ($op == 'list') {
28 $blocks[0]['info'] = t('Prev/Next node (all types)');
29 $blocks[1]['info'] = t('Prev/Next within node type');
30 if (module_exist('taxonomy')) {
31
32 if ($tid = variable_get('prevnext_2_tid', FALSE)) {
33 $term = taxonomy_get_term($tid);
34 $category = $term->name;
35 }
36 else {
37 $category = '['. l(t('configure'), 'admin/block/configure/prevnext/2') .']';
38 }
39 $blocks[2]['info'] = t('Prev/Next within the <em>%category</em> category.', array('%category' => $category));
40
41 if ($vid = variable_get('prevnext_3_vid', FALSE)) {
42 $vocab = taxonomy_get_vocabulary($vid);
43 $vocabulary = $vocab->name;
44 }
45 else {
46 $vocabulary = '['. l(t('configure'), 'admin/block/configure/prevnext/3') .']';
47 }
48 $blocks[3]['info'] = t('Prev/Next based on node\'s first term in the <em>%vocab</em> vocabulary', array('%vocab' => $vocabulary));
49
50 $blocks[4]['info'] = t('Prev/Next based on node\'s first term in any vocabulary');
51 }
52
53 if (module_exist('views')) {
54 if ($vid = variable_get('prevnext_5_view', FALSE)) {
55 $view = views_get_view($vid);
56 }
57 else {
58 $view->name = '['. l(t('configure'), 'admin/block/configure/prevnext/5') .']';
59 }
60 $blocks[5]['info'] = t('Prev/Next within the <em>%view</em> View', array('%view' => $view->name));
61 }
62
63 return $blocks;
64 }
65 else if ($op == 'configure') {
66 // all blocks have configurable title
67 $form['pn_title'] = array(
68 '#type' => 'textfield',
69 '#title' => 'Title',
70 '#default_value' => variable_get('prevnext_'. $delta .'_title', t('Previous/Next')),
71 '#description' => t('Title of this block as displayed on the page. Leave blank for no title.'),
72 );
73 $macros = implode(', ', array_keys(prevnext_replacements()));
74 $form['pn_template'] = array(
75 '#type' => 'textarea',
76 '#title' => 'Template',
77 '#default_value' => variable_get('prevnext_'. $delta .'_tpl', prevnext_default_template($delta>1)),
78 '#description' => t('Use <code>&lt;!--previous--&gt;</code>, <code>&lt;!--delimiter--&gt;</code>, and <code>&lt;!--next--&gt;</code> to separate the sections of the template. Replacement strings are: %macros', array('%macros' => $macros)),
79 '#rows' => 10,
80 );
81 switch ($delta) {
82 case 2:
83 $vocab_result = db_query('SELECT vid, name FROM {vocabulary} ORDER BY weight DESC, name ASC');
84 $options = array();
85 while ($vocab = db_fetch_object($vocab_result)) {
86 $term_result = db_query('SELECT tid, name FROM {term_data} WHERE vid = %d ORDER BY weight DESC, name ASC', $vocab->vid);
87 while ($term = db_fetch_object($term_result)) {
88 $options[$vocab->name][$term->tid] = $term->name;
89 }
90 }
91
92 if (!count($options)) {
93 $options[] = t('<no categories set>');
94 }
95 $form['pn_term'] = array(
96 '#type' => 'select',
97 '#multiple' => FALSE,
98 '#title' => 'Term',
99 '#options' => $options,
100 '#default_value' => variable_get('prevnext_'. $delta .'_tid', NULL),
101 );
102 break;
103
104 case 3:
105 $result = db_query('SELECT vid, name FROM {vocabulary} ORDER BY weight DESC, name ASC');
106 $options = array();
107 while($vocab = db_fetch_object($result)) {
108 $options[$vocab->vid] = $vocab->name;
109 }
110 if (!count($options)) {
111 $options[] = t('<no vocabularies set>');
112 }
113 $form['pn_vocab'] = array(
114 '#type' => 'select',
115 '#multiple' => FALSE,
116 '#title' => 'Vocabulary',
117 '#options' => $options,
118 '#default_value' => variable_get('prevnext_'. $delta .'_vocab', NULL),
119 );
120 break;
121
122 case 4:
123 // no extra settings
124 break;
125
126 case 5:
127 $result = db_query("SELECT vid, name FROM {view_view}");
128 $options = array();
129 while($view = db_fetch_object($result)) {
130 $options[$view->vid] = $view->name;
131 }
132 if (!count($options)) {
133 $options[] = t('<no views set>');
134 }
135 $form['pn_view'] = array(
136 '#type' => 'select',
137 '#multiple' => FALSE,
138 '#title' => 'View',
139 '#options' => $options,
140 '#default_value' => variable_get('prevnext_'. $delta .'_view', NULL),
141 '#description' => t('Select which View this block will be associated with.<br />DOES NOT CURRENTLY WORK WITH VIEWS REQUIRING ARGUMENTS.<br />DOES NOT WORK WITH NON-DISTINCT VIEWS.')
142 );
143 break;
144
145 }
146 return $form;
147 }
148 else if ($op == 'save') {
149
150 variable_set('prevnext_'. $delta .'_title', $edit['pn_title']);
151 variable_set('prevnext_'. $delta .'_tpl', $edit['pn_template']);
152
153 switch ($delta) {
154 case 2:
155 variable_set('prevnext_'. $delta .'_tid', $edit['pn_term']);
156 break;
157 case 3:
158 variable_set('prevnext_'. $delta .'_vid', $edit['pn_vocab']);
159 break;
160 case 5:
161 variable_set('prevnext_'. $delta .'_view', $edit['pn_view']);
162 break;
163 }
164 }
165 else if ($op == 'view') {
166 if (arg(0) == 'node' && is_numeric(arg(1))) {
167 $node = node_load(arg(1));
168 $block['subject'] = variable_get('prevnext_'. $delta .'_title', t('Previous/Next'));
169 switch ($delta) {
170 case 0:
171 $block['content'] = prevnext_node_all($node);
172 break;
173 case 1:
174 $block['content'] = prevnext_node_by_type($node);
175 break;
176 case 2:
177 $block['content'] = prevnext_node_by_term($node);
178 break;
179 case 3:
180 $block['content'] = prevnext_node_by_vocab($node);
181 break;
182 case 4:
183 $block['content'] = prevnext_node_any_term($node);
184 break;
185 case 5:
186 $block['content'] = prevnext_node_by_view($node);
187 break;
188 }
189 return $block;
190 }
191 }
192 }
193
194
195 /**
196 * Implementation of hook_help().
197 */
198 function prevnext_help($section) {
199 switch ($section) {
200 case 'admin/help#prevnext':
201 return t('TODO: Create admin help text.');
202 case 'admin/modules#description':
203 return t('Adds blocks with several types of previous/next links');
204 // OPTIONAL: Add additional cases for other paths that should display help text.
205 }
206 }
207
208 function prevnext_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
209 if (module_exist('views') && ($op == 'insert' || $op == 'update')) {
210 // clear the view cache
211 db_query('DELETE FROM {prevnext_view_cache}');
212 }
213 }
214
215
216 /**
217 * Find the next and previous nodes for a given node based on node id
218 *
219 * @param object $node
220 * node object of current node
221 * @return
222 * templated next and previous links
223 */
224 function prevnext_node_all($node) {
225 $prev = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n WHERE nid < %d AND status = 1 AND moderate = 0 ORDER BY nid DESC'), $node->nid));
226 $next = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n WHERE nid > %d AND status = 1 AND moderate = 0 ORDER BY nid ASC'), $node->nid));
227 // run the output through the template
228 return prevnext_template(0, $prev, $next, $node);
229 }
230
231 /**
232 * Find the next and previous nodes for a given node based on node id
233 *
234 * @param object $node
235 * node object of current node
236 * @return
237 * templated next and previous links
238 */
239 function prevnext_node_by_type($node) {
240 $prev = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n WHERE nid < %d AND type = "%s" AND status = 1 AND moderate = 0 ORDER BY nid DESC'), $node->nid, $node->type));
241 $next = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n WHERE nid > %d AND type = "%s" AND status = 1 AND moderate = 0 ORDER BY nid ASC'), $node->nid, $node->type));
242 // run the output through the template
243 return prevnext_template(1, $prev, $next, $node);
244 }
245
246 /**
247 * Find the next and previous nodes for a given node based on node id
248 *
249 * @param object $node
250 * node object of current node
251 * @return
252 * templated next and previous links
253 */
254 function prevnext_node_by_term($node) {
255 $delta = 2;
256 if ($tid = variable_get('prevnext_'. $delta .'_tid', NULL)) {
257 $term = taxonomy_get_term($tid);
258 $prev = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n INNER JOIN {term_node} tn ON tn.nid = n.nid WHERE n.nid < %d AND tn.tid = %d AND n.status = 1 AND n.moderate = 0 ORDER BY nid DESC'), $node->nid, $tid));
259 $next = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n INNER JOIN {term_node} tn ON tn.nid = n.nid WHERE n.nid > %d AND tn.tid = %d AND n.status = 1 AND n.moderate = 0 ORDER BY nid ASC'), $node->nid, $tid));
260 // run the output through the template
261 return prevnext_template($delta, $prev, $next, $node, $term);
262 }
263 else {
264 if (user_access('administer blocks')) {
265 return t('Please <a href="%url">configure</a> this block.', array('%url' => url('admin/block/configure/prevnext/'. $delta)));
266 }
267 }
268 }
269
270 /**
271 * Find the next and previous nodes for a given node based on node id
272 *
273 * @param object $node
274 * node object of current node
275 * @return
276 * templated next and previous links
277 */
278 function prevnext_node_by_vocab($node) {
279 $delta = 3;
280 if ($vid = variable_get('prevnext_'. $delta .'_vid', NULL)) {
281 $term = array_shift(taxonomy_node_get_terms_by_vocabulary($node->nid, $vid));
282 $tid = $term->tid;
283 $prev = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n INNER JOIN {term_node} tn ON tn.nid = n.nid WHERE n.nid < %d AND tn.tid = %d AND n.status = 1 AND n.moderate = 0 ORDER BY nid DESC'), $node->nid, $tid));
284 $next = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n INNER JOIN {term_node} tn ON tn.nid = n.nid WHERE n.nid > %d AND tn.tid = %d AND n.status = 1 AND n.moderate = 0 ORDER BY nid ASC'), $node->nid, $tid));
285 // run the output through the template
286 return prevnext_template($delta, $prev, $next, $node, $term);
287 }
288 else {
289 if (user_access('administer blocks')) {
290 return t('Please <a href="%url">configure</a> this block.', array('%url' => url('admin/block/configure/prevnext/'. $delta)));
291 }
292 }
293 }
294
295 function prevnext_node_any_term($node) {
296 $delta = 4;
297 if ($term = array_shift(taxonomy_node_get_terms($node->nid))) {
298 $tid = $term->tid;
299 $prev = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n INNER JOIN {term_node} tn ON tn.nid = n.nid WHERE n.nid < %d AND tn.tid = %d AND n.status = 1 AND n.moderate = 0 ORDER BY nid DESC'), $node->nid, $tid));
300 $next = db_fetch_object(db_query(db_rewrite_sql('SELECT n.* FROM {node} n INNER JOIN {term_node} tn ON tn.nid = n.nid WHERE n.nid > %d AND tn.tid = %d AND n.status = 1 AND n.moderate = 0 ORDER BY nid ASC'), $node->nid, $tid));
301 // run the output through the template
302 return prevnext_template($delta, $prev, $next, $node, $term);
303 }
304 }
305
306 function prevnext_node_by_view($node) {
307 $delta = 5;
308 if ($vid = variable_get('prevnext_'. $delta .'_view', NULL)) {
309 $view = views_load_view($vid);
310
311 // if the view is cached
312 if (db_result(db_query('SELECT vid FROM {prevnext_view_cache} WHERE vid = %d', $view->vid))) {
313 // try to select this node within the view
314 $index = db_result(db_query('SELECT idx FROM {prevnext_view_cache} WHERE vid = %d AND nid = %d', $view->vid, $node->nid));
315 }
316 else {
317 // get the list of node ids from the view
318 $list = views_build_view('items', $view);
319 // clear out any old stuff (if it exists)
320 db_query('DELETE FROM {prevnext_view_cache} WHERE vid = %d', $vid);
321 if (is_array($list['items'])) {
322 foreach($list['items'] as $key => $item) {
323 $return[$key] = $item->nid;
324 // store it in the cache
325 db_query('INSERT INTO {prevnext_view_cache} (vid, nid, idx) VALUES (%d, %d, %d)', $vid, $item->nid, $key);
326 }
327 $index = array_search($node->nid, $return);
328 }
329 }
330 // if the node is in the list
331 if ($index !== NULL && $index !== FALSE) {
332 if ($index != 0) { // if index is 0, then there's nothing previous
333 $prev_nid = $return ? $return[$index - 1] : db_result(db_query('SELECT nid FROM {prevnext_view_cache} WHERE vid = %d AND idx = %d', $view->vid, $index - 1));
334 if ($prev_nid) {
335 $prev_node = node_load($prev_nid);
336 }
337 }
338 // no easy way to test for last, so we just do the query
339 $next_nid = $return ? $return[$index + 1] : db_result(db_query('SELECT nid FROM {prevnext_view_cache} WHERE vid = %d AND idx = %d', $view->vid, $index + 1));
340 if ($next_nid) {
341 $next_node = node_load($next_nid);
342 }
343
344 return prevnext_template($delta, $prev_node, $next_node, $node, NULL, $view);
345
346 }
347 }
348 }
349
350 function prevnext_replacements(){
351 return array(
352 '%prev_title' => 'check_plain($prev_node->title)',
353 '%prev_url' => 'url("node/". $prev_node->nid)',
354 '%prev_id' => '$prev_node->nid',
355 '%prev_type' => '$prev_node->type',
356 '%next_title' => 'check_plain($next_node->title)',
357 '%next_url' => 'url("node/". $next_node->nid)',
358 '%next_id' => '$next_node->nid',
359 '%next_type' => '$next_node->type',
360 '%this_title' => '$node->title',
361 '%this_url' => 'url("node/". $node->nid)',
362 '%this_id' => '$node->nid',
363 '%this_type' => '$node->type',
364 '%term_name' => '$term->name',
365 '%view_name' => '$view->name',
366 '%view_desc' => '$view->description',
367 '%view_url' => 'url($view->url)',
368 '%view_id' => '$view->vid',
369 );
370 }
371
372 /**
373 * Output the templated version of the previous/next links
374 *
375 */
376 function prevnext_template($delta, $prev_node, $next_node, $node, $term = NULL, $view = NULL) {
377 $template = variable_get('prevnext_'. $delta .'_tpl', prevnext_default_template());
378
379 // eval the replacements
380 $replacements_raw = prevnext_replacements();
381 foreach ($replacements_raw as $key => $val) {
382 eval('$replacements["$key"] = '. $val .';');
383 }
384
385 // replace the macros
386 $template = strtr($template, $replacements);
387 if (!$prev_node) {
388 // no previous? strip out the code from <!--previous to <!--next
389 $template = preg_replace('/<!-- *?previous[\\w\\W]*(?=<!-- *next)/i', '', $template);
390 }
391 if (!$next_node) {
392 // no next? take out everything from delimiter (or next) onward
393 $template = preg_replace('/<!-- *?(next|delimiter)[\\w\\W]*/i', '', $template);
394 }
395 // remove the comments
396 $template = preg_replace('/<!-- *(previous|delimiter|next) *-->/i', '', $template);
397
398 return $template;
399 }
400
401 function prevnext_default_template($use_term = FALSE) {
402 $term = $use_term ? ' %term_name' : '';
403 $previous = t('previous');
404 $next = t('next');
405 $output =
406 <<<OUT
407 <!--previous-->
408 <div class="prev">
409 <div class="prevnext-label">$previous$term:</div>
410 <div class="prevnext-title"><a href="%prev_url">%prev_title</a></div>
411 </div>
412 <!--delimiter-->
413 <!--next-->
414 <div class="next">
415 <div class="prevnext-label">$next$term:</div>
416 <div class="prevnext-title"><a href="%next_url">%next_title</a></div>
417 </div>
418 OUT;
419 return $output;
420 }
421
422 /**
423 * Not used anymore. I'm going with a simple user-exposed templating system
424 */
425 function theme_prevnext($prev_node, $next_node) {
426 if ($prev_node) {
427 $output = '<span class="previous">'. l(t('previous'), 'node/'. $prev_node->nid) .'</span>';
428 }
429 if ($prev_node && $next_node) {
430 $output .= ' | ';
431 }
432 if ($next_node) {
433 $output .= '<span class="next">'. l(t('next'), 'node/'. $next_node->nid) .'</span>';
434 }
435 return $output;
436 }

  ViewVC Help
Powered by ViewVC 1.1.2