/[drupal]/contributions/modules/context/context_ui/context_ui.module
ViewVC logotype

Contents of /contributions/modules/context/context_ui/context_ui.module

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


Revision 1.13 - (show annotations) (download) (as text)
Wed Sep 3 02:12:27 2008 UTC (14 months, 3 weeks ago) by jmiccolis
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--1
Changes since 1.12: +12 -4 lines
File MIME type: text/x-php
Adding clone & override functionality to context_ui, for drupal 6 this time. Also made code E_ALL compliant and fixed other minor style issues.
1 <?php
2 // $Id: context_ui.module,v 1.12 2008/09/01 20:21:08 yhahn Exp $
3
4 /**
5 * Implementation of hook_init().
6 */
7 function context_ui_init() {
8 // Rebuild context_ui "cache".
9 if ($_GET['q'] == 'admin/build/modules') {
10 module_load_include('inc', 'context_ui', 'context_ui_admin');
11 context_ui_rebuild();
12 }
13 }
14
15 /**
16 * Implementation of hook_theme().
17 */
18 function context_ui_theme() {
19 $items['context_ui_form'] = array(
20 'arguments' => array('form' => array()),
21 'file' => 'context_ui_admin.inc',
22 );
23 $items['context_ui_block_ui'] = array(
24 'arguments' => array('form' => array()),
25 'file' => 'context_ui_admin.inc',
26 );
27 $items['context_ui_admin'] = array(
28 'arguments' => array('form' => array()),
29 'file' => 'context_ui_admin.inc',
30 );
31 $items['context_devel'] = array(
32 'arguments' => array('form' => array()),
33 );
34 $items['context_devel_recurse'] = array(
35 'arguments' => array('form' => array()),
36 );
37 $items['context_ui_menu_links'] = array(
38 'arguments' => array('links' => NULL, 'attributes' => array('class' => 'links')),
39 );
40 return $items;
41 }
42
43 /**
44 * Implementation of hook_block().
45 */
46 function context_ui_block($op = 'list', $delta = 0, $edit = array()) {
47 switch ($op) {
48 case 'list':
49 $blocks = array();
50 $blocks['devel']['info'] = t('Context Devel');
51 return $blocks;
52 case 'view':
53 switch ($delta) {
54 case 'devel':
55 $block = array();
56 $block['subject'] = t('Context Devel');
57 if ($context = context_get()) {
58 $output = theme('context_devel', $context);
59 $block['content'] = $output;
60 }
61 else {
62 $block['content'] = "<p>". t('No context information is set.') ."</p>";
63 }
64 return $block;
65 }
66 break;
67 }
68 }
69
70 /**
71 * Implementation of hook_context_items().
72 *
73 * Allows modules to integrate with context_ui and provide their native
74 * objects as options for setting/getting a context definition. The
75 * hook should return an array of items keyed on the object "type"
76 * (e.g. "node", "user", etc.) with key-value pairs corresponding to
77 * a FormAPI element array with some restrictions and additional info.
78 *
79 * '#title': Required. The title of the object / form option.
80 * '#type': Required. The FormAPI element type to use. Currently only
81 * 'select', 'checkboxes', 'radio', and 'textfield' are allowed.
82 * '#description': Optional. Help text to be displayed on the form.
83 * '#options': Required. A key-value array of options. They key will be
84 * stored and passed to context_ui_set(), so the integrating module
85 * should use a unique (within its namespace) / usable identifier.
86 * '#context_ui': Either 'setter' or 'getter'. Determines where this
87 * item will appear on the context_ui form.
88 */
89 function context_ui_context_items() {
90 $items = array();
91
92 // Content Types
93 $nodetypes = array();
94 foreach (node_get_types() as $type) {
95 $nodetypes[$type->type] = t($type->name); // @todo: this t() is wrong
96 }
97 $items['node'] = array(
98 '#title' => t('Content Types'),
99 '#description' => t('Set this context when viewing a node page or using the add/edit form of one of these content types.'),
100 '#options' => $nodetypes,
101 '#type' => 'checkboxes',
102 '#context_ui' => 'setter',
103 );
104
105 // Menu
106 if (module_exists('menu')) {
107 $menus = menu_parent_options(array_reverse(menu_get_menus()), NULL);
108 foreach ($menus as $key => $name) {
109 $id = explode(':', $key);
110 // @TODO: choose a good convention for excluding root menus from
111 // being selectable items
112 if ($id[1] == '0') {
113 // this is required because root menu names are displayed inside <> and will not be displayed otherwise
114 $menus['_'. $key] = '<strong>'. check_plain($name) .'</strong>';
115 }
116 else {
117 $link = menu_link_load($id[1]);
118 $menus[$link['path']] = $name;
119 }
120 unset($menus[$key]);
121 }
122 $items['menu'] = array(
123 '#title' => t('Menus'),
124 '#description' => t('Display the selected menu items as active when this context is set.'),
125 '#options' => $menus,
126 '#type' => 'radios',
127 '#context_ui' => 'getter',
128 );
129 }
130
131 // User
132 $items['user'] = array(
133 '#title' => t('User Pages'),
134 '#description' => t('Set this context when a user with selected role(s) is viewed'),
135 '#options' => user_roles(true),
136 '#type' => 'checkboxes',
137 '#context_ui' => 'setter',
138 );
139
140 // Book
141 if (module_exists('book')) {
142 $options = array();
143 foreach(book_get_books() as $book) {
144 $options[$book['menu_name']] = $book['title'];
145 }
146 $items['book'] = array(
147 '#title' => t('Book'),
148 '#description' => t('Set this context when a node in the selected book is viewed.'),
149 '#options' => $options,
150 '#type' => 'checkboxes',
151 '#context_ui' => 'setter',
152 );
153 }
154
155 return $items;
156 }
157
158 /**
159 * Implementation of hook_menu().
160 */
161 function context_ui_menu() {
162 $items['admin/build/context'] = array(
163 'title' => 'Context',
164 'description' => 'Associate menus, views, blocks, etc. with different contexts to structure your site.',
165 'page callback' => 'context_ui_admin',
166 'access callback' => 'user_access',
167 'access arguments' => array('administer site configuration'),
168 'type' => MENU_NORMAL_ITEM,
169 'file' => 'context_ui_admin.inc',
170 );
171 $items['admin/build/context/list'] = array(
172 'title' => 'List',
173 'page callback' => 'context_ui_admin',
174 'type' => MENU_DEFAULT_LOCAL_TASK,
175 'weight' => 0,
176 'file' => 'context_ui_admin.inc',
177 );
178 $items['admin/build/context/add'] = array(
179 'title' => 'Add Context',
180 'description' => 'Add a context to your site.',
181 'page callback' => 'drupal_get_form',
182 'page arguments' => array('context_ui_form', 'add'),
183 'access callback' => 'user_access',
184 'access arguments' => array('administer site configuration'),
185 'type' => MENU_LOCAL_TASK,
186 'weight' => 1,
187 'file' => 'context_ui_admin.inc',
188 );
189 $items['admin/build/context/import'] = array(
190 'title' => 'Import',
191 'description' => 'Import a context definition into your site.',
192 'page callback' => 'context_ui_import_page',
193 'access callback' => 'user_access',
194 'access arguments' => array('administer site configuration'),
195 'type' => MENU_LOCAL_TASK,
196 'weight' => 2,
197 'file' => 'context_ui_admin.inc',
198 );
199 $items['admin/build/context/edit'] = array(
200 'page callback' => 'drupal_get_form',
201 'page arguments' => array('context_ui_form', 'edit'),
202 'access callback' => 'user_access',
203 'access arguments' => array('administer site configuration'),
204 'type' => MENU_CALLBACK,
205 'file' => 'context_ui_admin.inc',
206 );
207 $items['admin/build/context/clone'] = array(
208 'page callback' => 'drupal_get_form',
209 'page arguments' => array('context_ui_form', 'clone'),
210 'access callback' => 'user_access',
211 'access arguments' => array('administer site configuration'),
212 'type' => MENU_CALLBACK,
213 'file' => 'context_ui_admin.inc',
214 );
215 $items['admin/build/context/view'] = array(
216 'page callback' => 'drupal_get_form',
217 'page arguments' => array('context_ui_form', 'view'),
218 'access callback' => 'user_access',
219 'access arguments' => array('administer site configuration'),
220 'type' => MENU_CALLBACK,
221 'file' => 'context_ui_admin.inc',
222 );
223 $items['admin/build/context/export'] = array(
224 'page callback' => 'drupal_get_form',
225 'page arguments' => array('context_ui_export'),
226 'access callback' => 'user_access',
227 'access arguments' => array('administer site configuration'),
228 'type' => MENU_CALLBACK,
229 'file' => 'context_ui_admin.inc',
230 );
231 $items['admin/build/context/delete'] = array(
232 'page callback' => 'drupal_get_form',
233 'page arguments' => array('context_ui_delete_confirm'),
234 'access callback' => 'user_access',
235 'access arguments' => array('administer site configuration'),
236 'type' => MENU_CALLBACK,
237 'file' => 'context_ui_admin.inc',
238 );
239
240 return $items;
241 }
242
243 /**
244 * Implementation of hook_help().
245 */
246 function context_ui_help($path, $arg) {
247 switch ($path) {
248 case 'admin/build/context':
249 return '<p>'.
250 t('Contexts provide you with a way to organize your site using terms familiar to real human beings. You can create a set of sections like <b>"News"</b>, <b>"Projects"</b>, <b>"Staff"</b>, and associate different technical aspects of Drupal to each section. For example, the <b>"News"</b> section may be a collection of <b>Nodes</b>, <b>Views</b>, <b>Menus</b> and <b>Blocks</b>.')
251 .'</p>';
252 break;
253 }
254 }
255
256 /**
257 * Implementation of hook_nodeapi().
258 */
259 function context_ui_nodeapi(&$node, $op, $teaser, $page) {
260 if ($op == 'view' && $page && arg(0) == 'node') {
261 // Implementation of context_ui_set for node.
262 context_ui_set('node', $node->type);
263
264 // Implementation of context_ui_set for book.
265 if (module_exists('book') && isset($node->book)) {
266 if ($node->book['menu_name']) {
267 context_ui_set('book', $node->book['menu_name']);
268 }
269 }
270 }
271 }
272
273 /**
274 * Implementation of hook_form_alter().
275 */
276 function context_ui_form_alter(&$form, $form_state, $form_id) {
277 if (isset($form['#node']) && arg(0) != 'admin') { // Prevent this from firing on admin pages... damn form driven apis...
278 context_ui_set('node', $form['#node']->type);
279 }
280 else if ($form_id == 'comment_form' && $nid = $form['nid']['#value']) {
281 $node = node_load($nid);
282 context_ui_set('node', $node->type);
283 }
284 else if ($form_id == 'block_admin_configure') {
285 // Display context_ui visibility information on block configuration pages
286 $module = $form['module']['#value'];
287 $delta = $form['delta']['#value'];
288
289 $result = db_query("SELECT cb.cid, cb.region, c.namespace, c.attribute, c.value FROM {context_ui_block} cb JOIN {context_ui} c ON cb.cid = c.cid WHERE cb.module = '%s' AND cb.delta = '%s' AND c.status = %d", $module, $delta, 1);
290
291 $rows = array();
292 while ($row = db_fetch_object($result)) {
293 $rows[] = array($row->namespace, $row->attribute, $row->value, $row->region, l(t('Edit visibility'), 'admin/build/context/edit/'. $row->cid, array('fragment' => 'context-ui-blocks')));
294 }
295 if ($rows) {
296 $content = theme('table', array(t('Namespace'), t('Attribute'), t('Value'), t('Region'), ''), $rows);
297 }
298 else {
299 $content = "<p>". t('No visibility rules have been set for this block using context_ui.') ."</p>";
300 }
301
302 $form['context_ui'] = array(
303 '#type' => 'fieldset',
304 '#title' => t('Context UI visibility'),
305 '#weight' => -1,
306 '#collapsible' => true,
307 );
308 $form['context_ui']['contexts'] = array(
309 '#type' => 'item',
310 '#value' => $content,
311 '#description' => t('To add or remove block visibility rules based on context, use the !context_admin.', array('!context_admin' => l(t('context administration page'), 'admin/build/context'))),
312 );
313 $form['block_settings']['#weight'] = -5;
314 }
315 }
316
317 /**
318 * Implementation of hook_user().
319 */
320 function context_ui_user($op, &$edit, &$account, $category = NULL) {
321 if ($op == 'view') {
322 context_ui_set('user', array_keys($account->roles));
323 }
324 }
325
326 /**
327 * Invokes hook_context_define() to collect all contexts provided in code by modules.
328 *
329 * @param $space
330 * An optional string namespace identifier. If provided, only context definitions with the
331 * specified namespace will be returned.
332 *
333 * @return
334 * An array of context objects.
335 */
336 function context_ui_defaults($namespace = null) {
337 static $contexts, $namespaces;
338 if (!$contexts) {
339 $contexts = array();
340 foreach (module_implements('context_define') as $module) {
341 $function = $module .'_context_define';
342 $contexts = array_merge($contexts, $function());
343 }
344 foreach ($contexts as $key => $context) {
345 $context = (object) $context;
346 $contexts[$key] = $context;
347 $namespaces[$context->namespace][] = $context;
348 }
349 }
350 if ($namespace) {
351 if (isset($namespaces[$namespace])) {
352 return $namespaces[$namespace];
353 }
354 else {
355 return array();
356 }
357 }
358 return $contexts;
359 }
360
361 /**
362 * Invokes hook_context_items() to provides an array of item types that a context may be associated with.
363 */
364 function context_ui_types($op = 'list') {
365 static $types;
366 if (!$types) {
367 $types = array();
368 foreach (module_implements('context_items') as $module) {
369 $function = $module .'_context_items';
370 $types = array_merge($types, $function());
371 }
372 }
373 switch ($op) {
374 case 'list':
375 return array_keys($types);
376 break;
377 case 'full':
378 return $types;
379 break;
380 }
381 }
382
383 /**
384 * Sets a namespace-attribute-value context that has been associated with the provided item.
385 *
386 * @param $type
387 * The item type to be matched. Any of the currently supported context items types ("view",
388 * "node", etc.) can be specified.
389 * @param $id
390 * An array of string or integer ids of the context item to match. Individual ids are also accepted.
391 *
392 * @return
393 * True if one or more contexts were set. False if no items/contexts matched.
394 */
395 function context_ui_set($type, $id) {
396 if (!is_array($id)) {
397 $id = array($id);
398 }
399 $set = false;
400 $result = db_query("
401 SELECT c.namespace, c.attribute, c.value, c.cid FROM {context_ui_item} ci
402 JOIN {context_ui} c ON ci.cid = c.cid
403 WHERE ci.type = '%s' AND ci.id IN (". substr(str_repeat("'%s',", count($id)), 0, -1) .") AND c.status = 1",
404 array_merge(array($type), $id));
405 while ($context = db_fetch_object($result)) {
406 // If this context already has a value, don't alter it.
407 if (!context_isset($context->namespace, $context->attribute)) {
408 context_set($context->namespace, $context->attribute, $context->value);
409
410 // Allow getters to respond to the set context
411 $context = context_ui_context('load', $context);
412 module_invoke_all('context_getter', $context);
413
414 // Store the cid of set contexts. Other parts of the stack may be interested.
415 $cid = context_get('context_ui', 'cid');
416 $cid = $cid ? $cid : array();
417 $cid[] = $context->cid;
418 context_set('context_ui', 'cid', $cid);
419 $set = true;
420 }
421 }
422 return $set;
423 }
424
425 /**
426 * Implementation of hook_context_getter().
427 */
428 function context_ui_context_getter($context) {
429 // Set active menu context
430 context_ui_menu_set_location($context);
431 }
432
433 /**
434 * Takes a retrieved context array and returns a themed out tree representation of that context.
435 */
436 function theme_context_devel($context) {
437 drupal_add_css(drupal_get_path("module", "context_ui") ."/context_ui.css");
438 $output = '';
439 foreach ($context as $space => $a) {
440 $output .= "<div class='context-devel-space'>$space</div>";
441 $output .= "<div class='context-devel-tree'>". theme_context_devel_recurse($a) ."</div>";
442 }
443 return $output;
444 }
445
446 /**
447 * Helper function to theme_context_devel that recurses down context arrays and themes accordingly.
448 */
449 function theme_context_devel_recurse($value) {
450 $output = '';
451 if (is_array($value) || is_object($value)) {
452 if (is_array($value)) {
453 $type = 'array';
454 }
455 else if (is_object($value)) {
456 $type = 'object';
457 }
458 foreach ((array)$value as $key => $a) {
459 $output .= "<div class='context-devel-wrapper'><label><small>$type</small>$key</label>". theme('context_devel_recurse', $a) ."</div>";
460 }
461 }
462 else {
463 if (is_string($value)) {
464 $type = 'string';
465 }
466 else if (is_int($value)) {
467 $type = 'int';
468 }
469 else if (is_bool($value)) {
470 $type = 'bool';
471 }
472 $output .= "<div class='context-devel-wrapper'><label><small>$type</small>$value</label></div>";
473 }
474 return $output;
475 }
476
477 /**
478 * The D6 menu system no longer permits the kind of hackish grafting of
479 * the menu tree that was possible in D5. While breadcrumb trails can
480 * still be altered, menu_navigation_links() determines the active
481 * trail of menu items through other (read: unalterable) means.
482 *
483 * To make use of the context_ui menu functionality, you must use
484 * either theme_context_ui_menu_links() or implement your own theme
485 * function/override that checks against the active paths.
486 */
487 function context_ui_menu_set_location($context) {
488 if ($context->cid) {
489 $result = db_query("
490 SELECT ci.id
491 FROM {context_ui_item} ci
492 WHERE ci.type = '%s' AND ci.cid = %d",
493 'menu', $context->cid);
494 if ($path = db_result($result)) {
495 $active_paths = context_get('context_ui', 'active_paths');
496 $active_paths = $active_paths ? $active_paths : array();
497 $active_paths[] = $path;
498 context_set('context_ui', 'active_paths', $active_paths);
499 }
500 }
501 }
502
503 /**
504 * Theme function for enabling context based active classes on menu
505 * items. This is a simple wrapper around theme_links() that adds a
506 * simple check against active contexts before passing actual markup
507 * duties onto theme_links() or its overrides.
508 */
509 function theme_context_ui_menu_links($links, $attributes = array('class' => 'links')) {
510 // Retrieve active paths set by context_ui
511 $active_paths = context_get('context_ui', 'active_paths');
512 $active_paths = $active_paths ? $active_paths : array();
513
514 $modified_links = array();
515 foreach ($links as $key => $link) {
516 // Add active class to both links and key if path is active
517 if (in_array($link['href'], $active_paths)) {
518 $key .= ' active';
519 $link['attributes']['class'] .= ' active';
520 }
521 $modified_links[$key] = $link;
522 }
523
524 // Pass modified links onto theme_links() for actual theming duties
525 return theme('links', $modified_links, $attributes);
526 }
527
528 /**
529 * In order to add blocks we need to intercept theme_blocks and build the block
530 * content using an diffrent process. The current implementation assumes that
531 * the theme layer isn't going to define either 'phptemplate_blocks' or
532 * 'themename_blocks'.
533 */
534 function phptemplate_blocks($region) {
535 $output = "";
536 if ($list = context_ui_block_list($region)) {
537 foreach ($list as $key => $block) {
538 $output .= theme("block", $block);
539 }
540 }
541 // Add any content assigned to this region through drupal_set_content() calls.
542 $output .= drupal_get_content($region);
543 return $output;
544 }
545
546 /**
547 * An alternative version of block_list() that provides any context_ui enabled blocks.
548 */
549 function context_ui_block_list($region) {
550 global $user, $theme_key;
551
552 static $cids = array();
553 static $blocks = array();
554
555 if (!count($blocks)) {
556 // generate list of active DB contexts
557 // formerly an API function -- TODO: evaluate whether this may be useful otherwise
558 $result = db_query("SELECT * FROM {context_ui} WHERE status = 1", 'context_ui');
559 while ($context = db_fetch_object($result)) {
560 if (context_get($context->namespace, $context->attribute) == $context->value) {
561 $cids[$context->cid] = $context->cid;
562 }
563 }
564
565 $rids = array_keys($user->roles);
566 $result = db_query(db_rewrite_sql("
567 SELECT DISTINCT b.*, c.weight AS context_weight, c.region AS context_region, c.cid
568 FROM {blocks} b
569 LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta
570 LEFT JOIN {context_ui_block} c ON b.module = c.module AND b.delta = c.delta
571 WHERE b.theme = '%s' AND (r.rid IN (". db_placeholders($rids) .") OR r.rid IS NULL)
572 ORDER BY b.region, b.weight, b.module", 'b', 'bid'),
573 array_merge(array($theme_key), $rids)
574 );
575 while ($block = db_fetch_object($result)) {
576 // we determine status as a combination of DB setting + context definition
577 $status = FALSE;
578 // prepare context blocks
579 // if cid is in active contexts, use context weight + region
580 if (isset($block->cid) && in_array($block->cid, $cids)) {
581 $block->context_ui = TRUE;
582 $block->region = $block->context_region ? $block->context_region : $block->region;
583 $block->weight = $block->context_weight ? $block->context_weight : $block->weight;
584 $status = TRUE;
585 }
586 // use db setting
587 else {
588 $status = $block->status;
589 }
590
591 if ($status) {
592 if (!isset($blocks[$block->region])) {
593 $blocks[$block->region] = array();
594 }
595 $enabled = _context_ui_block_visibility('user', $block);
596 $page_match = _context_ui_block_visibility('page', $block);
597 $throttle = _context_ui_block_visibility('throttle', $block);
598 if ($enabled && $page_match && $throttle) {
599 // Try fetching the block from cache. Block caching is not compatible with
600 // node_access modules. We also preserve the submission of forms in blocks,
601 // by fetching from cache only if the request method is 'GET'.
602 if (!count(module_implements('node_grants')) && $_SERVER['REQUEST_METHOD'] == 'GET' && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
603 $array = $cache->data;
604 }
605 else {
606 $array = module_invoke($block->module, 'block', 'view', $block->delta);
607 if (isset($cid)) {
608 cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
609 }
610 }
611
612 if (isset($array) && is_array($array) && isset($array['content'])) {
613 foreach ($array as $k => $v) {
614 $block->$k = $v;
615 }
616 // Override default block title if a custom display title is present.
617 if ($block->title) {
618 // Check plain here to allow module generated titles to keep any markup.
619 $block->subject = $block->title == '<none>' ? '' : check_plain($block->title);
620 }
621 $blocks[$block->region]["{$block->module}_{$block->delta}"] = $block;
622 }
623 }
624 }
625 }
626 // Custom sort since SQL order by won't give it to us for free
627 foreach ($blocks as $key => $region_blocks) {
628 uasort($region_blocks, '_context_ui_block_compare');
629 $blocks[$key] = $region_blocks;
630 }
631 }
632 // Create an empty array if there were no entries
633 if (!isset($blocks[$region])) {
634 $blocks[$region] = array();
635 }
636 return $blocks[$region];
637 }
638
639 function _context_ui_block_visibility($op, $block) {
640 switch ($op) {
641 case 'user':
642 global $user;
643 // Use the user's block visibility setting, if necessary
644 if ($block->custom != 0) {
645 if ($user->uid && isset($user->block[$block->module][$block->delta])) {
646 return $user->block[$block->module][$block->delta];
647 }
648 else {
649 return ($block->custom == 1);
650 }
651 }
652 return true;
653 case 'page':
654 // Match path if necessary
655 if ($block->pages) {
656 if ($block->visibility < 2) {
657 $path = drupal_get_path_alias($_GET['q']);
658 $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($block->pages, '/')) .')$/';
659 // Compare with the internal and path alias (if any).
660 $page_match = drupal_match_path($path, $block->pages);
661 if ($path != $_GET['q']) {
662 $page_match = $page_match || drupal_match_path($_GET['q'], $block->pages);
663 }
664 // When $block->visibility has a value of 0, the block is displayed on
665 // all pages except those listed in $block->pages. When set to 1, it
666 // is displayed only on those pages listed in $block->pages.
667 return !($block->visibility xor $page_match);
668 }
669 else {
670 return drupal_eval($block->pages);
671 }
672 }
673 return true;
674 case 'throttle':
675 if (!($block->throttle && (module_invoke('throttle', 'status') > 0))) {
676 return true;
677 }
678 return false;
679 }
680 }
681
682 /**
683 * Helper function to sort block objects by weight
684 */
685 function _context_ui_block_compare($a, $b) {
686 // Enabled blocks
687 return ($a->weight - $b->weight);
688 }
689
690 /**
691 * Provides simple operations (load/insert/update/etc.) on a core context space/key/value definition.
692 *
693 * @param $op
694 * Operation to perform on a context. May be one of load/insert/update/delete.
695 * @param $context
696 * A context object. Optionally, can be an integer cid for the "load" operation.
697 *
698 * @return
699 * If loading, returns a full context item. All other operations return true on success and false on failure.
700 */
701 function context_ui_context($op, $context) {
702 switch ($op) {
703 case 'load':
704 static $cache = array();
705 // Argument is a cid
706 if (is_numeric($context)) {
707 if (!isset($cache[$context])) {
708 $context = db_fetch_object(db_query("SELECT * FROM {context_ui} WHERE cid = %d", $context));
709 }
710 else {
711 return $cache[$context];
712 }
713 }
714 // Context object has an associated cid
715 else if (is_object($context) && isset($context->cid)) {
716 if (!isset($cache[$context->cid])) {
717 $context = db_fetch_object(db_query("SELECT * FROM {context_ui} WHERE cid = %d", $context->cid));
718 }
719 else {
720 return $cache[$context->cid];
721 }
722 }
723 // Context object has no cid -- we'll try to load by ns/attr/val
724 else if (is_object($context) && $context->namespace && $context->attribute && $context->value) {
725 $args = array(
726 $context->namespace,
727 $context->attribute,
728 $context->value,
729 );
730 $system = '';
731 $status = '';
732 if (isset($context->system)) {
733 $args[] = $context->system;
734 $system = "AND system = %d";
735 }
736 if (isset($context->status) && $context->status != 0) {
737 $args[] = $context->status;
738 $status = "AND status = %d";
739 }
740 $context = db_fetch_object(db_query("SELECT * FROM {context_ui} WHERE namespace = '%s' AND attribute = '%s' AND value = '%s' $system $status", $args));
741 }
742 if ($context) {
743 $context = context_ui_item('load', $context);
744 $context = context_ui_item_block('load', $context);
745 // After all that hard work, cache the context
746 $cache[$context->cid] = $context;
747 return $context;
748 }
749 return false;
750 case 'insert':
751 // check for type & existence of context definition
752 $existing = context_ui_context('load', $context);
753 if (!$existing || $existing->system != $context->system) {
754 $values = array(
755 'system' => $context->system,
756 'status' => $context->status,
757 'namespace' => $context->namespace,
758 'attribute' => $context->attribute,
759 'value' => $context->value,
760 );
761 $keys = implode(', ', array_keys($values));
762 $args = array_merge(array($keys), $values);
763 $result = db_query("INSERT INTO {context_ui} (%s) VALUES(%d, %d, '%s', '%s', '%s')", $args);
764 $context->cid = db_last_insert_id('context_ui', 'cid');
765 $result = $result && context_ui_item('save', $context);
766 $result = $result && context_ui_item_block('save', $context);
767 return $result ? true : false;
768 }
769 return false;
770 break;
771 case 'update':
772 if ($context->cid) {
773 // update core context information
774 $values = array(
775 'system' => $context->system,
776 'status' => $context->status,
777 'namespace' => $context->namespace,
778 'attribute' => $context->attribute,
779 'value' => $context->value,
780 'cid' => $context->cid,
781 );
782 $keys = implode(', ', array_keys($values));
783 $result = db_query("UPDATE {context_ui} SET system = %d, status = %d, namespace = '%s', attribute = '%s', value = '%s'WHERE cid = %d", $values);
784 $result = $result && context_ui_item('save', $context);
785 $result = $result && context_ui_item_block('save', $context);
786 return $result ? true : false;
787 }
788 break;
789 case 'delete':
790 if ($context = context_ui_context('load', $context)) {
791 db_query("DELETE FROM {context_ui} WHERE cid = %d", $context->cid);
792 db_query("DELETE FROM {context_ui_item} WHERE cid = %d", $context->cid);
793 db_query("DELETE FROM {context_ui_block} WHERE cid = %d", $context->cid);
794 return true;
795 }
796 return false;
797 }
798 }
799
800 /**
801 * Provides simple operations (load/save) on any context-item associations. context_ui_item() will
802 * automatically sync the database with the context object provided when saving. Any associations
803 * that exist on the object that are absent from the database will be inserted, and any associations
804 * that are missing will be removed from the database.
805 *
806 * @param $op
807 * Operation to perform on a context. May be either load or save.
808 * @param $context
809 * A context object with item associations.
810 *
811 * @return
812 * Load returns a context object with item associations. Save returns true on success and false on failure.
813 */
814 function context_ui_item($op = 'load', $context) {
815 if ($context->cid) {
816 switch ($op) {
817 case 'load':
818 $result = db_query("SELECT * FROM {context_ui_item} WHERE cid = %d", $context->cid);
819 while ($row = db_fetch_object($result)) {
820 $context->{$row->type}[$row->id] = $row->id;
821 }
822 return $context;
823 case 'save':
824 $current = new stdClass();
825 $current->cid = $context->cid;
826 $current = context_ui_item('load', $current);
827 foreach (context_ui_types() as $type) {
828 // Delete any stale associations
829 if (isset($current->{$type}) && is_array($current->{$type})) {
830 foreach ($current->{$type} as $id) {
831 $delete = false;
832 if (!is_array($context->{$type})) {
833 $delete = true;
834 }
835 else if (array_search($id, $context->{$type}) === false) {
836 $delete = true;
837 }
838 if ($delete) {
839 $result = db_query("DELETE FROM {context_ui_item} WHERE cid = %d AND type = '%s' AND id = '%s'", $context->cid, $type, $id);
840 }
841 }
842 }
843 // Add/update any missing associations
844 if (isset($context->{$type}) && is_array($context->{$type})) {
845 foreach ($context->{$type} as $id) {
846 $update = false;
847 if (!(isset($current->{$type}) && is_array($current->{$type}))) {
848 $update = true;
849 }
850 else if (array_search($id, $current->{$type}) === false) {
851 $update = true;
852 }
853 if ($update) {
854 $result = db_query("REPLACE INTO {context_ui_item} (cid, type, id) VALUES(%d, '%s', '%s')", $context->cid, $type, $id);
855 }
856 }
857 }
858 }
859 return true;
860 break;
861 }
862 }
863 return false;
864 }
865
866 /**
867 * Provides simple operations (load/save) on any context-block associations. Parallel usage as
868 * context_ui_item().
869 *
870 * @param $op
871 * Operation to perform on a context. May be either load or save.
872 * @param $context
873 * A context object with an array of blocks at $context->block.
874 *
875 * @return
876 * Load returns a context object with block information. Save returns true on success and false on failure.
877 */
878 function context_ui_item_block($op = 'load', $context) {
879 if ($context->cid) {
880 switch ($op) {
881 case 'load':
882 $result = db_query("SELECT module, delta, region, weight FROM {context_ui_block} WHERE cid = %d", $context->cid);
883 $context->block = array();
884 while ($block = db_fetch_object($result)) {
885 $bid = $block->module ."_". $block->delta;
886 $block->bid = $bid;
887 $context->block[$bid] = $block;
888 }
889 return $context;
890 break;
891 case 'save':
892 // grab the current context-> block associations
893 $current = (object) array('cid' => $context->cid);
894 $current = context_ui_item_block('load', $current);
895 // compare current definition with new definition. remove missing associations from the DB
896 if (is_array($current->block)) {
897 foreach ($current->block as $block) {
898 if (!isset($context->block[$block->bid]) || $current->block[$block->bid] != $context->block[$block->bid]) {
899 $result = db_query("DELETE FROM {context_ui_block WHERE cid = %d AND module = '%s' AND delta = '%s'", $context->cid, $block->module, $block->delta);
900 }
901 }
902 }
903 // compare new definition with current definition. add missing associations to the DB
904 if (is_array($context->block)) {
905 foreach ($context->block as $block) {
906 $block = (object) $block;
907 if (!isset($current->block[$block->bid]) || $current->block[$block->bid] != $context->block[$block->bid]) {
908 $args = array(
909 'module' => $block->module,
910 'delta' => $block->delta,
911 'region' => $block->region,
912 'weight' => $block->weight,
913 'cid' => $context->cid,
914 );
915 $result = db_query("REPLACE INTO {context_ui_block} (module, delta, region, weight, cid) VALUES ('%s', '%s', '%s', %d, %d)", $args);
916 }
917 }
918 }
919 return true;
920 break;
921 }
922 }
923 return false;
924 }
925
926 /**
927 * Generates a themed set of links for node types associated with
928 * the current active contexts.
929 */
930 function theme_context_ui_node_links() {
931 $output = '';
932 $links = _context_ui_node_links();
933 foreach ($links as $link) {
934 $output .= l('+ '. t('Add !type', array('!type' => $link['title'])), $link['href'], array('class' => 'button'));
935 }
936 return $output;
937 }
938
939 /**
940 * Generates an array of links (suitable for use with theme_links)
941 * to the node forms of types associated with current active contexts.
942 */
943 function _context_ui_node_links($resest = false) {
944 static $links;
945 if (!$links || $reset) {
946 $links = array();
947 if ($cids = context_get('context_ui', 'cid')) {
948 // Collect types
949 $types = node_get_types();
950 // Iterate over active contexts
951 foreach ($cids as $cid) {
952 $context = context_ui_context('load', $cid);
953 if (is_array($context->node)) {
954 foreach ($context->node as $type) {
955 if (isset($types[$type]) && node_access('create', $type)) {
956 $links[$type] = array(
957 'title' => $types[$type]->name,
958 'href' => 'node/add/'. $type,
959 );
960 }
961 }
962 }
963 }
964 }
965 }
966 return $links;
967 }

  ViewVC Help
Powered by ViewVC 1.1.2