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

Contents of /contributions/modules/pressflow_placement/pressflow_placement.module

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


Revision 1.1 - (show annotations) (download) (as text)
Sun Apr 1 07:29:48 2007 UTC (2 years, 7 months ago) by straussd
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
File MIME type: text/x-php
PressFlow Placement
1 <?php
2 function pressflow_placement_node_info() {
3 return array(
4 'pressflow_placement' => array(
5 'name' => t('Placement block'),
6 'module' => 'pressflow_placement',
7 'description' => t('Create an editorially controlled block of teasers.'),
8 )
9 );
10 }
11
12 function pressflow_placement_menu($may_cache)
13 {
14 $items = array();
15 if (!$may_cache) {
16 if (arg(0) == 'node' && is_numeric(arg(1)))
17 {
18 $node = node_load(arg(1));
19 $possible_placements = pressflow_placement_get_eligible($node);
20 if (!empty($possible_placements)) {
21 $items[] = array(
22 'path' => 'node/' . $node->nid . '/place',
23 'title' => t('Place'),
24 'callback' => 'pressflow_placement_place',
25 'callback arguments' => array($node->nid),
26 'type' => MENU_LOCAL_TASK,
27 'access' => TRUE,
28 );
29
30 if (is_numeric(arg(3))) {
31 $items[] = array(
32 'path' => 'node/' . $node->nid . '/place/',
33 'title' => t('Place content'),
34 'type' => MENU_CALLBACK,
35 'access' => TRUE,
36 'callback' => 'pressflow_placement_place',
37 'callback arguments' => array($node->nid, arg(3)),
38 );
39 }
40 }
41 }
42 }
43
44 return $items;
45 }
46
47 function pressflow_placement_block($op = 'list', $delta = 0, $edit = array()) {
48 switch ($op) {
49 case 'list':
50 $res = db_query('SELECT nid, title FROM {node} WHERE type = "pressflow_placement"');
51 $blocks = array();
52 while ($node = db_fetch_object($res))
53 {
54 $blocks[$node->nid]['info'] = 'PressFlow Placement: ' . $node->title;
55 }
56 //print_r($blocks);
57
58 return $blocks;
59 case 'view': default:
60 $node = node_load($delta);
61 $block = array('title' => $node->title, 'content' => '');
62 foreach($node->teasers as $nid => $teaser)
63 {
64 $block['content'] .= $teaser . '<br/>';
65 }
66 return $block;
67 }
68 }
69
70 function pressflow_placement_content_form($nid, $into_nid, $delete_nid, $insert_after_nid) {
71 $form = array();
72
73 $form['nid'] = array(
74 '#type' => 'hidden',
75 '#value' => $nid,
76 );
77
78 $form['into_nid'] = array(
79 '#type' => 'hidden',
80 '#value' => $into_nid,
81 );
82
83 $form['delete_nid'] = array(
84 '#type' => 'hidden',
85 '#value' => $delete_nid,
86 );
87
88 $form['insert_after_nid'] = array(
89 '#type' => 'hidden',
90 '#value' => $insert_after_nid,
91 );
92
93 $teaser = '';
94
95 $into_node = node_load($into_nid);
96 if (isset($into_node->teasers[$nid]))
97 {
98 $teaser = $into_node->teasers[$nid];
99 $source = 'current custom teaser';
100 }
101
102 if ($teaser == '') {
103 $node = node_load($nid);
104 $teaser = $node->teaser;
105 $source = 'standard teaser for this node';
106 }
107
108 $form['teaser'] = array(
109 '#type' => 'textarea',
110 '#title' => t('Custom teaser for %title in the block %into_title', array('%title' => $node->title, '%into_title' => $into_node->title)),
111 '#required' => TRUE,
112 '#default_value' => $teaser,
113 '#description' => t('The initial text above is the %source.', array('%source' => $source)),
114 );
115
116 $form[] = array(
117 '#type' => 'submit',
118 '#value' => t('Place content'),
119 );
120
121 return $form;
122 }
123
124 function pressflow_placement_content_form_submit($form_id, $form_values) {
125 $into_node = node_load($form_values['into_nid']);
126 //drupal_set_message(print_r($into_node->teasers, TRUE));
127
128 $teasers = array();
129 if ($form_values['insert_after_nid'] == 0)
130 {
131 $teasers[$form_values['nid']] = $form_values['teaser'];
132 }
133 foreach($into_node->teasers as $teaser_nid => $teaser)
134 {
135 // Don't return nids to the teaser set if they're deleted or being replaced
136 if ($teaser_nid != $form_values['delete_nid'] && $teaser_nid != $form_values['nid']) {
137 $teasers[$teaser_nid] = $teaser;
138 }
139 if ($form_values['insert_after_nid'] == $teaser_nid) {
140 $teasers[$form_values['nid']] = $form_values['teaser'];
141 }
142 }
143 $into_node->teasers = $teasers;
144 $into_node->revision = TRUE;
145
146 //drupal_set_message(print_r($form_values, TRUE));
147 //drupal_set_message(print_r($into_node, TRUE));
148 node_save($into_node);
149 drupal_set_message(t('%into_title has been updated.', array('%into_title' => $into_node->title)));
150 return 'node/' . $form_values['nid'];
151 }
152
153 function pressflow_placement_place($nid, $into_nid = NULL, $delete_nid = NULL, $insert_after_nid = NULL) {
154 $node = node_load($nid);
155
156 $possible_placements = pressflow_placement_get_eligible($node);
157
158 $output = '';
159
160 // Pick the placement block
161 if (!isset($into_nid))
162 {
163 drupal_set_title(t('Place %title', array('%title' => $node->title)));
164 $output .= '<h3>' . t('Where would you like to place this content?') . '</h3>';
165 $links = array();
166 foreach($possible_placements as $into_nid => $title) {
167 $into_node = node_load($into_nid);
168 $link = array();
169 $link['title'] = $title;
170 $nids_in_placement = count($into_node->teasers);
171 //drupal_set_message($title);
172 // If the block isn't full, there's no need to remove anything
173 if ($nids_in_placement < $into_node->max_nodes) {
174 $link['href'] = 'node/' . $nid . '/place/' . $into_nid . '/0';
175 //If there's only one slot or all are empty, the placement choice is obvious
176 if ($into_node->max_nodes == 1 || $nids_in_placement == 0) {
177 $link['href'] .= '/0';
178 }
179 }
180 // If there's only one slot, the choice for deletion and placement are obvious
181 else if ($into_node->max_nodes == 1) {
182 $delete_nids = array_keys($into_node->teasers);
183 $link['href'] = 'node/' . $nid . '/place/' . $into_nid . '/' . $delete_nids[0] . '/0';
184 }
185 // If the nid is already in the block, remove it
186 else if (isset($into_node->teasers[$nid])) {
187 $link['href'] = 'node/' . $nid . '/place/' . $into_nid . '/' . $nid;
188 // If such a removal makes the choice for placement obvious, do it
189 if ($nids_in_placement == 1) {
190 $link['href'] .= '/0';
191 }
192 }
193 else {
194 $link['href'] = 'node/' . $nid . '/place/' . $into_nid;
195 }
196
197 $links[] = $link;
198 }
199 $output .= theme('placement_options', $links, 'block');
200 }
201
202 // Pick the item to remove
203 else if (!isset($delete_nid)) {
204 $into_node = node_load($into_nid);
205 drupal_set_title(t('Place %title into %into_title', array('%title' => $node->title, '%into_title' => $into_node->title)));
206 if (!isset($possible_placements[$into_nid])) {
207 drupal_access_denied();
208 return;
209 }
210
211 $output .= '<h3>' . t('The current block is full. What would you like to remove?') . '</h3>';
212
213 $links = array();
214 foreach ($into_node->teasers as $delete_nid => $delete_content)
215 {
216 $delete_node = node_load($delete_nid);
217 $links[] = array(
218 'title' => t('Remove %title', array('%title' => $delete_node->title)),
219 'href' => 'node/' . $nid . '/place/' . $into_nid . '/' . $delete_nid,
220 'html' => TRUE,
221 );
222 }
223
224 $output .= theme('placement_options', $links, 'delete');
225 $output .= theme('placement_options_back', $nid);
226 }
227
228 // Pick where to put the new item
229 else if (!isset($insert_after_nid)) {
230 $into_node = node_load($into_nid);
231 drupal_set_title(t('Place %title into %into_title', array('%title' => $node->title, '%into_title' => $into_node->title)));
232 if (!isset($possible_placements[$into_nid])) {
233 drupal_access_denied();
234 return;
235 }
236
237 $output .= '<h3>' . t('Where would you like to place the new item?') . '</h3>';
238
239 $links = array();
240 $add_text = t('Add %title here', array('%title' => $node->title));
241 $links[] = array(
242 'title' => $add_text,
243 'href' => 'node/' . $nid . '/place/' . $into_nid . '/' . $delete_nid . '/0',
244 );
245 foreach ($into_node->teasers as $insert_after_nid => $insert_after_teaser)
246 {
247 // Don't offer to place after the removed nid
248 if ($insert_after_nid != $delete_nid) {
249 $insert_after_node = node_load($insert_after_nid);
250 $src = url(drupal_get_path('module', 'pressflow_placement')) . '/icons/doc-option-tab.png';
251 $links[] = array(
252 'title' => '<div style="border: 1px solid rgb(200,200,200); width: 300px;"><div style="width: 290px; background-color: rgb(200,200,200); font-weight: bold; padding: 5px;"><img src="'. $src . '" alt="Node" />' . $insert_after_node->title . '</div><div style="padding: 5px;">' . $into_node->teasers[$insert_after_nid] . '</div></div>',
253 );
254 $links[] = array(
255 'title' => $add_text,
256 'href' => 'node/' . $nid . '/place/' . $into_nid . '/' . $delete_nid . '/' . $insert_after_nid,
257 'html' => TRUE,
258 );
259 }
260 }
261
262 $output .= theme('placement_options', $links, 'insert');
263 $output .= theme('placement_options_back', $nid);
264 }
265
266 // Pick whether to place the teaser or custom content
267 else {
268 $into_node = node_load($into_nid);
269 if ($insert_after_nid > 0) {
270 $insert_after_node = node_load($insert_after_nid);
271 drupal_set_title(t('Place %title into %into_title after %insert_after_title', array('%title' => $node->title, '%into_title' => $into_node->title, '%insert_after_title' => $insert_after_node->title)));
272 }
273 else {
274 drupal_set_title(t('Place %title into %into_title at the top', array('%title' => $node->title, '%into_title' => $into_node->title)));
275 }
276 $output .= drupal_get_form('pressflow_placement_content_form', $nid, $into_nid, $delete_nid, $insert_after_nid);
277 $output .= theme('placement_options_back', $nid);
278 }
279
280
281 return $output;
282 }
283
284 function pressflow_placement_perm() {
285 return array('create placement block', 'edit own placement block', 'edit placement block', 'view placement block as a node', 'delete placement block');
286 }
287
288 function pressflow_placement_access($op, $node) {
289 global $user;
290
291 if ($op == 'view') {
292 return user_access('view placement blocks as a node');
293 }
294
295 if ($op == 'create') {
296 return user_access('create placement block');
297 }
298
299 if ($op == 'update') {
300 if (user_access('edit placement block') || (user_access('edit own placement block') && ($user->uid == $node->uid))) {
301 return TRUE;
302 }
303 }
304
305 if ($op == 'delete') {
306 return user_access('delete placement block');
307 }
308 }
309
310 function pressflow_placement_get_eligible($node) {
311 if (!user_access('edit placement block') && !user_access('edit own placement block')) {
312 return array();
313 }
314
315 static $cache = array();
316 if (isset($cache[$node->nid]))
317 return $cache[$node->nid];
318
319 // Ensure a consistent snapshot
320 $txn = new pressflow_transaction();
321
322 // Find all pressflow placement nodes that can hold the $node->type
323 $res = db_query('SELECT n.nid FROM node n INNER JOIN pressflow_placement p ON n.vid = p.vid WHERE p.node_type = "%s" ORDER BY n.title', $node->type);
324
325 $eligible = array();
326 while($row = db_fetch_object($res))
327 {
328 $placement_node = node_load($row->nid);
329
330 // Check that the current user can "update" the placement node
331 //if (node_access('update', $placement_node)) {
332 $eligible[$placement_node->nid] = $placement_node->title;
333 //}
334 }
335
336 $cache[$node->nid] = $eligible;
337
338 return $eligible;
339 }
340
341 function pressflow_placement_form(&$node) {
342 $type = node_get_types('type', $node);
343
344 // We need to define form elements for the node's title and body.
345 $form['title'] = array(
346 '#type' => 'textfield',
347 '#title' => check_plain($type->title_label),
348 '#required' => TRUE,
349 '#default_value' => $node->title,
350 '#weight' => -5,
351 );
352
353 $max_nodes = $node->max_nodes;
354 if ($max_nodes == '')
355 $max_nodes = 1;
356
357 $form['max_nodes'] = array(
358 '#type' => 'textfield',
359 '#title' => t('Number of slots'),
360 '#required' => TRUE,
361 '#default_value' => $max_nodes,
362 '#size' => 10,
363 '#maxlength' => 10,
364 );
365
366 $raw_node_types = node_get_types('types');
367 $node_types = array();
368
369 // Show as empty for new nodes
370 if ($node->node_type == '')
371 $node_types[''] = '';
372
373 foreach($raw_node_types as $name => $attributes)
374 {
375 if ($name != 'pressflow_placement')
376 $node_types[$name] = $attributes->name;
377 }
378
379 $form['node_type'] = array(
380 '#type' => 'select',
381 '#title' => t('Restrict to content type'),
382 '#required' => TRUE,
383 '#default_value' => $node->node_type,
384 '#options' => $node_types,
385 );
386
387 return $form;
388 }
389
390 function pressflow_placement_load($node) {
391 $additions = db_fetch_object(db_query('SELECT * FROM {pressflow_placement} WHERE vid = %d', $node->vid));
392
393 $res = db_query('SELECT teaser_nid, teaser FROM {pressflow_placement_teasers} WHERE vid = %d ORDER BY weight', $node->vid);
394 $additions->teasers = array();
395 while ($teaser = db_fetch_object($res))
396 {
397 //drupal_set_message(print_r($teaser, TRUE));
398 $additions->teasers[$teaser->teaser_nid] = $teaser->teaser;
399 }
400 //drupal_set_message(print_r($additions->teasers, TRUE));
401 return $additions;
402 }
403
404 function pressflow_placement_nodeapi(&$node, $op, $teaser, $page) {
405 $txn = new pressflow_transaction();
406 switch ($op) {
407 case 'delete revision':
408 $res = db_query('DELETE FROM {pressflow_placement} WHERE vid = %d', $node->vid);
409 $txn->rollback_if_false($res);
410
411 $res = db_query('DELETE FROM {pressflow_placement_teasers} WHERE vid = %d', $node->vid);
412 $txn->rollback_if_false($res);
413 break;
414 }
415 }
416
417 function pressflow_placement_insert($node) {
418 $txn = new pressflow_transaction();
419
420 $res = db_query('INSERT INTO {pressflow_placement} (vid, nid, max_nodes, node_type) VALUES (%d, %d, %d, "%s")', $node->vid, $node->nid, $node->max_nodes, $node->node_type);
421 $txn->rollback_if_false($res);
422
423 if (is_array($node->teasers))
424 {
425 $weight = 1;
426 foreach($node->teasers as $teaser_nid => $teaser)
427 {
428 $res = db_query('INSERT INTO {pressflow_placement_teasers} (vid, nid, weight, teaser_nid, teaser) VALUES (%d, %d, %d, %d, "%s")', $node->vid, $node->nid, $weight, $teaser_nid, $teaser);
429 $txn->rollback_if_false($res);
430 $weight++;
431 }
432 }
433 }
434
435 function pressflow_placement_delete($node) {
436 $txn = new pressflow_transaction();
437
438 $res = db_query('DELETE FROM {pressflow_placement} WHERE nid = %d', $node->nid);
439 $txn->rollback_if_false($res);
440
441 $res = db_query('DELETE FROM {pressflow_placement_teasers} WHERE nid = %d', $node->nid);
442 $txn->rollback_if_false($res);
443 }
444
445 function pressflow_placement_update($node) {
446 $txn = new pressflow_transaction();
447
448 if ($node->revision) {
449 //drupal_set_message('Creating revision');
450 pressflow_placement_insert($node);
451 } else {
452 // Delete the current revision...
453 pressflow_placement_nodeapi($node, 'delete revision', FALSE, FALSE);
454 // ...and replace it
455 pressflow_placement_insert($node);
456 }
457 }
458
459 function pressflow_placement_validate(&$node) {
460 if ($node->max_nodes) {
461 if (!is_numeric($node->max_nodes)) {
462 form_set_error('max_nodes', t('The maximum number of nodes must be a number.'));
463 }
464 }
465 else {
466 // Let an empty field mean "zero."
467 $node->max_nodes = 1;
468 }
469 }
470
471 function pressflow_placement_view($node, $teaser = FALSE, $page = FALSE) {
472 $node = node_prepare($node, $teaser);
473 return $node;
474 }
475
476 function theme_placement_options($links, $op = 'block') {
477 $output = '<p>';
478 $img = url(drupal_get_path('module', 'pressflow_placement')) . '/icons/';
479 if ($op == 'block') {
480 $img .= 'folder-open-blue.png';
481 }
482 else if ($op == 'delete') {
483 $img .= 'doc-option-remove.png';
484 }
485 else if ($op == 'insert') {
486 $img .= 'doc-option-add.png';
487 }
488
489 foreach($links as $link)
490 {
491 if (isset($link['href']))
492 {
493 $title = '<div><img src="' . $img . '" alt="' . $op . '" /> ' . $link['title'];
494 $output .= l($title, $link['href'], array(), NULL, NULL, FALSE, TRUE) . '</div>' . "\n";
495 } else {
496 $output .= '<div style="margin-top: 10px; margin-bottom: 10px;">' . $link['title'] . '</div>' . "\n";
497 }
498 }
499 $output .= '</p>';
500
501 return $output;
502 }
503
504 function theme_placement_options_back($nid)
505 {
506 $img = url(drupal_get_path('module', 'pressflow_placement')) . '/icons/arrow-single-left-green.png';
507 $title = '<img src="' . $img . '" alt="Start over" /> Start over';
508 return '<p><hr />' . l($title, 'node/' . $nid . '/place', array(), NULL, NULL, FALSE, TRUE) . '</p>';
509 }

  ViewVC Help
Powered by ViewVC 1.1.2