| 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 |
}
|