Skip to content
Snippets Groups Projects
Commit b44374f6 authored by Bostjan Kovac's avatar Bostjan Kovac
Browse files

Revert "Clean up Drupal 7 code, prepare for Drupal 8 push."

This reverts commit a1cedf59.
parent a1cedf59
No related branches found
No related tags found
No related merge requests found
Showing
with 3124 additions and 0 deletions
API.txt 0 → 100644
Context 3.x API
---------------
The following is an overview of using the Context API.
The context static cache
------------------------
Context provides a centralized set of API functions for setting and retrieving a
static cache:
// Set a static cache value at [my_namspace][mykey]
context_set('my_namespace', 'mykey', $value);
// Retrieve a static cache value at [my_namespace][mykey]
context_get('my_namespace', 'mykey'); // $value
// Boolean for whether there is a value at [my_namespace][mykey]
context_isset('my_namespace', 'mykey'); // TRUE
These are used internally by context but may also be used by other modules. Just
do not use the namespace `context` unless you want to affect things that context
is up to.
Adding a condition or reaction plugin
-------------------------------------
Both context conditions and reactions utilize the CTools plugins API. In order
to add a new condition or reaction for your module, follow these steps:
1. Implement `hook_context_plugins()` to define your plugins, classes, and class
hierarchy.
function mymodule_context_plugins() {
$plugins = array();
$plugins['mymodule_context_condition_bar'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'mymodule') .'/plugins',
'file' => 'mymodule_context_condition_bar.inc',
'class' => 'mymodule_context_condition_bar',
'parent' => 'context_condition',
),
);
return $plugins;
}
2. Implement `hook_context_registry()` to define your conditions and/or
reactions and map them to plugins.
function mymodule_context_registry() {
return array(
'conditions' => array(
'bar' => array(
'title' => t('Name of condition "bar"'),
'plugin' => 'mymodule_context_condition_bar',
),
),
);
}
3. Write your condition or reaction plugin class. It's best to look at one of
the included plugins as a starting point.
4. Create a Drupal integration point for your plugin. A node page condition
plugin, for example, may be invoked from `hook_node_view()`. Typically a
Drupal integration point for a condition uses a Drupal hook to trigger
tests that determine whether context conditions are met for one or more
plug-ins. For example, this is how the context module itself uses
hook_init():
function context_init() {
if ($plugin = context_get_plugin('condition', 'path')) {
$plugin->execute();
}
if ($plugin = context_get_plugin('condition', 'language')) {
global $language;
$plugin->execute($language->language);
}
if ($plugin = context_get_plugin('condition', 'user')) {
global $user;
$plugin->execute($user);
}
}
This function first instantiates the Context module's path condition
plugin (filename context_condition_path.inc in the plugins directory),
and then uses that plugin's execute() method. The execute() method
determine whether any path conditions are met and, if so, it activates
the contexts that match those conditions. After setting contexts based
path conditions, the context_init() function then does the same thing
with the Context module's language and user condition plugins.
Replacing or extending existing plugins
---------------------------------------
You can replace a condition or reaction plugin with your own plugin class using
`hook_context_registry_alter()`:
function mymodule_context_registry_alter(&$registry) {
if (!empty($registry['conditions']['node'])) {
$registry['conditions']['node']['plugin'] = 'mymodule_context_condition_customnode';
}
}
This entry would swap out the default node condition plugin for a custom one
provided by `mymodule`. Note that any replacement plugins must have an entry in
`hook_context_plugins()`.
Current state of Context for Drupal 7
-------------------------------------
Context for D7 is a straight port of Context 3.x from D6. There are no major
API changes and any exported contexts from D6 should be compatible with the D7
version. You will need the latest CTools (as of Sept. 16 2010) from here:
- http://github.com/sdboyer/ctools
### Working
- all conditions except node taxonomy condition
- all reactions
- context UI
- context layouts
- inline editor (see the context_ui README file for info on enabling)
### Expect API changes
- node taxonomy condition to generic field condition for entities
Context 3.x for Drupal 7.x
--------------------------
Context allows you to manage contextual conditions and reactions for
different portions of your site. You can think of each context as
representing a "section" of your site. For each context, you can choose
the conditions that trigger this context to be active and choose different
aspects of Drupal that should react to this active context.
Think of conditions as a set of rules that are checked during page load
to see what context is active. Any reactions that are associated with
active contexts are then fired.
Installation
------------
Context can be installed like any other Drupal module -- place it in
the modules directory for your site and enable it (and its requirement,
CTools) on the `admin/modules` page.
You will probably also want to install Context UI which provides a way for
you to edit contexts through the Drupal admin interface.
Example
-------
You want to create a "pressroom" section of your site. You have a press
room view that displays press release nodes, but you also want to tie
a book with media resources tightly to this section. You would also
like a contact block you've made to appear whenever a user is in the
pressroom section.
1. Add a new context on admin/structure/context
2. Under "Conditions", associate the pressroom nodetype, the pressroom view,
and the media kit book with the context.
3. Under "Reactions > Menu", choose the pressroom menu item to be set active.
4. Under "Reactions > Blocks", add the contact block to a region.
5. Save the context.
For a more in-depth overview of the UI components, see the Context UI
`README.txt`.
Hooks
-----
See `context.api.php` for the hooks made available by context and `API.txt` for
usage examples.
Maintainers
-----------
- yhahn (Young Hahn)
- jmiccolis (Jeff Miccolis)
- Steven Jones
Contributors
------------
- alex_b (Alex Barth)
- dmitrig01 (Dmitri Gaskin)
- Pasqualle (Csuthy Bálint)
<?php
/**
* @file
* Hooks provided by Context.
*/
/**
* CTools plugin API hook for Context. Note that a proper entry in
* hook_ctools_plugin_api() must exist for this hook to be called.
*/
function hook_context_plugins() {
$plugins = array();
$plugins['foo_context_condition_bar'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'foo') .'/plugins',
'file' => 'foo_context_condition_bar.inc',
'class' => 'foo_context_condition_bar',
'parent' => 'context_condition',
),
);
$plugins['foo_context_reaction_baz'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'foo') .'/plugins',
'file' => 'foo_context_reaction_baz.inc',
'class' => 'foo_context_reaction_baz',
'parent' => 'context_reaction',
),
);
return $plugins;
}
/**
* Registry hook for conditions & reactions.
*
* Each entry associates a condition or reaction with the CTools plugin to be
* used as its plugin class.
*/
function hook_context_registry() {
return array(
'conditions' => array(
'bar' => array(
'title' => t('Name of condition "bar"'),
'plugin' => 'foo_context_condition_bar',
),
),
'reactions' => array(
'baz' => array(
'title' => t('Name of reaction "baz"'),
'plugin' => 'foo_context_reaction_baz',
),
),
);
}
/**
* Execute Context page conditions
*
* Allows modules to hook into Context's hook_page_build to execute their
* conditions at an appropriate time before the firing of reactions.
*/
function hook_context_page_condition() {
if ($plugin = context_get_plugin('condition', 'bar')) {
$plugin->execute();
}
}
/**
* Execute Context page reactions
*
* Allows modules to hook into Context's hook_page_build to execute their
* reactions at an appropriate time after the firing of conditions.
*/
function hook_context_page_reaction() {
if ($plugin = context_get_plugin('reaction', 'baz')) {
$plugin->execute();
}
}
/**
* Alter the registry.
*
* Allows modules to alter the registry. Default plugins can be replaced by
* custom ones declared in hook_context_plugins().
*
* @param $registry
* The registry, passed by reference.
*/
function hook_context_registry_alter(&$registry) {
if (isset($registry['reactions']['baz'])) {
$registry['reactions']['baz']['plugin'] = 'custom_context_reaction_baz';
}
}
/**
* Alter/add a condition to a node-related event.
*
* Allows modules to add one or more context condition plugin executions to a
* node view, form, etc.
*
* @param $node
* The node object.
* @param $op
* The node-related operation: 'node', 'form', 'comment'.
*/
function hook_context_node_condition_alter(&$node, $op) {
if ($plugin = context_get_plugin('condition', 'bar')) {
$plugin->execute($node, $op);
}
}
/**
* Alter a context directly after it has been loaded. Allows modules to alter
* a context object's reactions. While you may alter conditions, this will
* generally have no effect as conditions are cached for performance and
* contexts are loaded after conditions are checked, not before.
*
* @param &$context
* The context object by reference.
*/
function hook_context_load_alter(&$context) {
if ($context->name === 'foo' && isset($context->reactions['block'])) {
$context->reactions['block']['blocks']['locale-0'] = array(
'module' => 'locale',
'delta' => '0',
'region' => 'header',
'weight' => '2',
);
}
}
/**
* Allows for finer grained access mechanisms to using the json
* rendering capabilities of the block reaction when a user isn't
* granted the administer contexts or context ajax block access
* permission
* @param $block_id
* ID of block in module-delta format
*/
function hook_context_allow_ajax_block_access($block_id) {
}
<?php
/**
* Implementation of hook_help().
*/
function context_help($path, $arg) {
switch ($path) {
case 'admin/help#context':
$output = file_get_contents(drupal_get_path('module', 'context') . '/README.txt');
return module_exists('markdown') ? filter_xss_admin(module_invoke('markdown', 'filter', 'process', 0, -1, $output)) : '<pre>' . check_plain($output) . '</pre>';
}
}
/**
* Implementation of hook_theme().
*/
function context_theme() {
$items = array();
if (!module_exists('block')) {
$items['block'] = array(
'render element' => 'elements',
'template' => 'block',
'path' => drupal_get_path('module', 'block'),
'file' => 'block.module',
'template' => 'block',
);
}
$items['context_block_form'] = array(
'render element' => 'form',
'path' => drupal_get_path('module', 'context') . '/theme',
'file' => 'context_reaction_block.theme.inc',
);
$items['context_block_regions_form'] = array(
'render element' => 'form',
'path' => drupal_get_path('module', 'context') . '/theme',
'file' => 'context_reaction_block.theme.inc',
);
$items['context_block_editor'] = array(
'render element' => 'form',
'path' => drupal_get_path('module', 'context') . '/theme',
'file' => 'context_reaction_block.theme.inc',
);
$items['context_block_browser'] = array(
'variables' => array('blocks' => array(), 'context' => array()),
'path' => drupal_get_path('module', 'context') . '/theme',
'template' => 'context-block-browser',
'file' => 'context_reaction_block.theme.inc',
);
$items['context_block_browser_item'] = array(
'variables' => array('block' => array()),
'path' => drupal_get_path('module', 'context') . '/theme',
'template' => 'context-block-browser-item',
'file' => 'context_reaction_block.theme.inc',
);
$items['context_block_script_placeholder'] = array(
'variables' => array('text' => NULL),
'path' => drupal_get_path('module', 'context') . '/theme',
'file' => 'context_reaction_block.theme.inc',
);
$items['context_block_edit_wrap'] = array(
'render element' => 'element',
'path' => drupal_get_path('module', 'context') . '/theme',
'file' => 'context_reaction_block.theme.inc',
);
return $items;
}
/**
* Implementation of hook_theme_registry_alter().
*/
function context_theme_registry_alter(&$theme_registry) {
// Push theme_page() through a context_preprocess to provide
// context-sensitive menus and variables. Ensure that
// context_preprocess_page() comes immediately after
// template_preprocess_page().
$position = array_search('context_preprocess_page', $theme_registry['page']['preprocess functions']);
if ($position !== FALSE) {
unset($theme_registry['page']['preprocess functions'][$position]);
}
// Prevent conflict with i18n_menu.
if (module_exists('i18n_menu')) {
$position = array_search('i18n_menu_preprocess_page', $theme_registry['page']['preprocess functions']);
}
else {
$position = array_search('template_preprocess_page', $theme_registry['page']['preprocess functions']);
}
$position = $position ? $position + 1 : 2;
array_splice($theme_registry['page']['preprocess functions'], $position, 0, 'context_preprocess_page');
}
/**
* Implementation of hook_ctools_render_alter().
* Used to detect the presence of a page manager node view or node form.
*/
function context_ctools_render_alter($info, $page, $data) {
extract($data);
if ($page && in_array($task['name'], array('node_view', 'node_edit'), TRUE)) {
foreach ($contexts as $ctools_context) {
if (in_array('node', $ctools_context->type) && !empty($ctools_context->data)) {
context_node_condition($ctools_context->data, $task['name'] === 'node_view' ? 'view' : 'form');
break;
}
}
}
}
/**
* Implementation of hook_entity_prepare_view().
*/
function context_entity_prepare_view($prepare, $entity_type) {
if ($entity_type === 'taxonomy_term' && count($prepare) === 1) {
$term = reset($prepare);
$menu = menu_get_object('taxonomy_term', 2);
if ($menu && $term->tid == $menu->tid && $plugin = context_get_plugin('condition', 'taxonomy_term')) {
$plugin->execute($term, 'view');
}
}
}
/**
* Implementation of hook_node_view().
*/
function context_node_view($node, $view_mode) {
$object = menu_get_object();
if (isset($object->nid) && $object->nid === $node->nid) {
context_node_condition($node, 'view');
}
}
/**
* Implementation of hook_form_alter().
*/
function context_form_alter(&$form, $form_state, $form_id) {
// If the form is an admin for, flag it so that we can force a rebuild if needed.
if (path_is_admin($_GET['q'])) {
$form['#submit'][] = 'context_admin_form_submit';
}
// Trigger the condition in an after_build function to avoid being skipped
// when there are validation errors.
$form['#after_build'][] = 'context_form_alter_node_after_build';
}
/**
* Form #after_build callback for context_form_alter().
*/
function context_form_alter_node_after_build($form, &$form_state) {
// Prevent this from firing on admin pages... damn form driven apis...
if (!empty($form['#node_edit_form']) && arg(0) != 'admin') {
context_node_condition($form['#node'], 'form');
}
return $form;
}
/**
* Clear out block info cache when an admin area form is submitted.
*/
function context_admin_form_submit(&$form, $form_state) {
if ($plugin = context_get_plugin('reaction', 'block')) {
$plugin->rebuild_needed(TRUE);
}
}
/**
* Centralized node condition call function for the ever increasing number of
* ways to get at a node view / node form.
*/
function context_node_condition(&$node, $op) {
if ($plugin = context_get_plugin('condition', 'node')) {
$plugin->execute($node, $op);
}
if (module_exists('taxonomy')) {
if ($plugin = context_get_plugin('condition', 'node_taxonomy')) {
$plugin->execute($node, $op);
}
}
if (module_exists('book')) {
if ($plugin = context_get_plugin('condition', 'book')) {
$plugin->execute($node, $op);
}
if ($plugin = context_get_plugin('condition', 'bookroot')) {
$plugin->execute($node, $op);
}
}
// Allow other plugins to easily be triggered on node-related events.
drupal_alter('context_node_condition', $node, $op);
}
/**
* Implementation of hook_form_alter() for system_modules_form.
*/
function context_form_system_modules_form_alter(&$form, $form_state) {
context_invalidate_cache();
}
/**
* Implementation of hook_form_alter() for user_profile_form.
*/
function context_form_user_profile_form_alter(&$form, $form_state) {
if ($plugin = context_get_plugin('condition', 'user_page')) {
$plugin->execute($form['#user'], 'form');
}
}
/**
* Implementation of hook_form_alter() for user_register_form.
*/
function context_form_user_register_form_alter(&$form, $form_state) {
if ($plugin = context_get_plugin('condition', 'user_page')) {
$plugin->execute($form['#user'], 'register');
}
}
/**
* Implementation of hook_form_alter() for comment_form.
*/
function context_form_comment_form_alter(&$form, $form_state) {
if ($nid = $form['nid']['#value']) {
$node = node_load($nid);
context_node_condition($node, 'comment');
}
}
/**
* Implementation of hook_views_pre_view().
*/
function context_views_pre_view($view, $display) {
if ($plugin = context_get_plugin('condition', 'views')) {
$plugin->execute($view);
}
// Support Views overrides of specific entity paths.
if ($view->display_handler->has_path()) {
switch ($view->display_handler->get_option('path')) {
case 'taxonomy/term/%':
if (($term = taxonomy_term_load(arg(2))) && ($plugin = context_get_plugin('condition', 'taxonomy_term'))) {
$plugin->execute($term, 'view');
}
break;
case 'node/%':
if ($node = node_load(arg(1))) {
context_node_condition($node, 'view');
}
break;
case 'user/%':
if (($account = user_load(arg(1))) && ($plugin = context_get_plugin('condition', 'user_page'))) {
$plugin->execute($account, 'view');
}
break;
}
}
}
/**
* Implementation of hook_user().
*/
function context_user_view($account, $view_mode) {
if ($view_mode === 'full' && $plugin = context_get_plugin('condition', 'user_page')) {
$plugin->execute($account, 'view');
}
}
/**
* Implements hook_page_build().
*/
function context_page_build(&$page) {
module_invoke_all('context_page_condition');
module_invoke_all('context_page_reaction');
if ($plugin = context_get_plugin('reaction', 'block')) {
$plugin->execute($page);
}
// See block_page_build. Clear static cache b/c in overlay form submissions
// hook_page_build can get called more than once per page load.
drupal_static_reset('context_reaction_block_list');
}
/**
* THEME FUNCTIONS & RELATED ==========================================
*/
/**
* Generates an array of links (suitable for use with theme_links)
* to the node forms of types associated with current active contexts.
*/
function context_links($reset = FALSE) {
static $links;
if (!$links || $reset) {
$contexts = context_active_contexts();
$active_types = array();
$conditions = array('node', 'bookroot');
foreach ($conditions as $condition) {
foreach ($contexts as $k => $v) {
if (!empty($v->conditions[$condition]['values'])) {
$active_types = array_merge($active_types, array_filter($v->conditions[$condition]['values']));
}
}
}
$links = array();
if (!empty($active_types)) {
// Iterate over active contexts
foreach ($active_types as $type) {
$add_url = 'node/add/' . str_replace('_', '-', $type);
$item = menu_get_item($add_url);
if ($item && $item['access'] && strpos($_GET['q'], $add_url) !== 0) {
$links[$type] = array('title' => t('Add @type', array('@type' => node_type_get_name($type))), 'href' => $add_url);
}
}
}
drupal_alter('context_links', $links);
uasort($links, 'element_sort');
}
return $links;
}
/**
* Implementation of hook_context_page_condition().
*/
function context_context_page_condition() {
if ($plugin = context_get_plugin('condition', 'menu')) {
$plugin->execute();
}
if ($plugin = context_get_plugin('condition', 'default')) {
$plugin->execute(1);
}
if ($plugin = context_get_plugin('condition', 'context')) {
$plugin->execute();
}
if ($plugin = context_get_plugin('condition', 'context_all')) {
$plugin->execute();
}
}
/**
* Implementation of hook_context_page_reaction().
*/
function context_context_page_reaction() {
if ($plugin = context_get_plugin('reaction', 'css_injector')) {
$plugin->execute();
}
if ($plugin = context_get_plugin('reaction', 'debug')) {
$plugin->execute();
}
}
/**
* Implementation of hook_preprocess_page().
*/
function context_preprocess_page(&$vars) {
if ($plugin = context_get_plugin('reaction', 'theme')) {
$plugin->execute($vars);
}
if ($plugin = context_get_plugin('reaction', 'template_suggestions')) {
$plugin->execute($vars);
}
/*
if ($context_links = context_links()) {
$vars['context_links'] = theme('links', $context_links);
}
else {
$vars['context_links'] = '';
}
*/
}
/**
* Implementation of hook_delivery_callback_alter().
* Based on menu_position's and menu_trail_by_path's implementations.
*/
function context_page_delivery_callback_alter() {
if ($plugin = context_get_plugin('reaction', 'menu')) {
$plugin->execute();
}
if ($plugin = context_get_plugin('reaction', 'breadcrumb')) {
$plugin->execute();
}
}
/**
* Implementation of hook_preprocess_html().
*/
function context_preprocess_html(&$vars) {
if ($plugin = context_get_plugin('reaction', 'theme_html')) {
$plugin->execute($vars);
}
}
name = "Context"
dependencies[] = "ctools"
description = "Provide modules with a cache that lasts for a single page request."
package = "Context"
core = "7.x"
files[] = tests/context.test
files[] = tests/context.conditions.test
files[] = tests/context.reactions.test
<?php
/**
* Implementation of hook_install().
*/
function context_install() {
// Nothing todo...
}
/**
* Implementation of hook_uninstall().
*/
function context_uninstall() {
drupal_uninstall_schema('context');
variable_del('context_ui_show_empty_regions');
variable_del('context_reaction_block_disable_core');
variable_del('context_reaction_block_all_regions');
}
/**
* Implementation of hook_schema().
*/
function context_schema() {
$schema = array();
$schema['context'] = array(
'description' => 'Storage for normal (user-defined) contexts.',
'export' => array(
'key' => 'name',
'identifier' => 'context',
'default hook' => 'context_default_contexts', // Function hook name.
'status' => 'context_status',
'api' => array(
'owner' => 'context',
'api' => 'context', // Base name for api include files.
'minimum_version' => 3,
'current_version' => 3,
),
'export callback' => 'context_export',
),
'fields' => array(
'name' => array(
'description' => 'The primary identifier for a context.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'description' => array(
'description' => 'Description for this context.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'tag' => array(
'description' => 'Tag for this context.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'conditions' => array(
'description' => 'Serialized storage of all context condition settings.',
'type' => 'text',
'serialize' => TRUE,
),
'reactions' => array(
'description' => 'Serialized storage of all context reaction settings.',
'type' => 'text',
'serialize' => TRUE,
),
'condition_mode' => array(
'description' => 'Condition mode for this context.',
'type' => 'int',
'default' => 0,
),
),
'primary key' => array('name'),
);
return $schema;
}
/**
* Update 7000: Handle adjustments to split of theme reaction to support D7 preprocess split between _page and _html
*/
function context_update_7000() {
drupal_load('module', 'ctools');
drupal_load('module', 'context');
$updated = array();
$contexts = context_load(NULL, TRUE);
foreach ($contexts as $c) {
// if the old data is in the old reaction and the new reaction hasn't been saved, migrate the old data to the new reaction
if (isset($c->reactions['theme']) &&
isset($c->reactions['theme']['class']) &&
!empty($c->reactions['theme']['class']) &&
!isset($c->reactions['theme_html'])
) {
$c->reactions['theme_html']['class'] = $c->reactions['theme']['class'];
context_save($c);
$updated[] = $c->name;
}
}
if (empty($updated)) {
$ret = t('No contexts requiring migration detected');
}
else {
$ret = t('The following contexts had theme reaction data migrated: @names', array('@names' => join(', ', $updated)));
}
return $ret;
}
<?php
require('context.core.inc');
define('CONTEXT_GET', 0);
define('CONTEXT_SET', 1);
define('CONTEXT_ISSET', 2);
define('CONTEXT_CLEAR', 3);
define('CONTEXT_CONDITION_MODE_OR', 0);
define('CONTEXT_CONDITION_MODE_AND', 1);
/**
* Master context function. Avoid calling this directly -- use one of the helper functions below.
*
* @param $op
* The operation to perform - handled by the context helper functions. Use them.
* @param $namespace
* A string to be used as the namespace for the context information.
* @param $attribute
* Usually a string to be used as a key to set/retrieve context information. An array can
* also be used when setting context to establish an entire context namespace at once.
* (At some point objects may also be accepted, but currently functionaliy isn't complete.)
* @param $value
* A value to set for the provided key. If omitted the value will be set to true.
*
* @return
* Either the requested value, or false if the operation fails.
*/
function context_context($op = CONTEXT_GET, $namespace = NULL, $attribute = NULL, $value = NULL) {
static $context;
$context = !$context ? array() : $context;
switch ($op) {
case CONTEXT_GET:
// return entire context
if (!$namespace) {
return $context;
}
// return entire space if set
elseif (isset($context[(string) $namespace])) {
// return val of key from space
if (is_array($context[(string) $namespace]) && isset($context[(string) $namespace][(string) $attribute])) {
return $context[(string) $namespace][(string) $attribute];
}
elseif (!$attribute) {
return $context[(string) $namespace];
}
}
break;
case CONTEXT_SET:
// bail if invalid space is specified or context is already set
if (is_string($namespace) || is_int($namespace)) {
// initialize namespace if no key is specified
if (!$attribute) {
$context[(string) $namespace] = array();
return TRUE;
}
// set to true if key is a usable identifier. otherwise, allow a key or object to be inserted
if ($value === NULL) {
if (is_string($attribute) || is_int($attribute)) {
$context[(string) $namespace][(string) $attribute] = TRUE;
return TRUE;
}
elseif (is_array($attribute) || is_object($attribute)) {
$context[(string) $namespace] = $attribute;
return TRUE;
}
}
// set value if key is valid
if ((is_string($attribute) || is_int($attribute)) && $value !== NULL) {
$context[$namespace][$attribute] = $value;
return TRUE;
}
}
break;
case CONTEXT_ISSET:
// return entire context
if (!$namespace) return FALSE;
if (!$attribute) {
// return entire space if set
return isset($context[$namespace]);
}
// return val of key from space
return isset($context[$namespace][$attribute]);
case CONTEXT_CLEAR:
$context = array();
return TRUE;
}
return FALSE;
}
/**
* Sets a context by namespace + attribute.
*/
function context_set($namespace, $attribute = NULL, $value = NULL) {
return context_context(CONTEXT_SET, $namespace, $attribute, $value);
}
/**
* Retrieves a context by namespace + (optional) attribute.
*/
function context_get($namespace = NULL, $attribute = NULL) {
return context_context(CONTEXT_GET, $namespace, $attribute, NULL);
}
/**
* Returns a boolean for whether a context namespace + attribute have been set.
*/
function context_isset($namespace = NULL, $attribute = NULL) {
return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);
}
/**
* Deprecated context_exists() function. Retained for backwards
* compatibility -- please use context_isset() instead.
*/
function context_exists($namespace = NULL, $attribute = NULL) {
return context_context(CONTEXT_ISSET, $namespace, $attribute, NULL);
}
/**
* Clears static context array() -- meant only for testing
*/
function context_clear() {
return context_context(CONTEXT_CLEAR);
}
/**
* Implemented hooks ==================================================
*/
/**
* Implementation of hook_ctools_plugin_type().
*/
function context_ctools_plugin_type() {
return array(
'plugins' => array(
'cache' => TRUE,
'use hooks' => TRUE,
'classes' => array('handler'),
),
);
}
/**
* Implementation of hook_context_plugins().
*
* This is a ctools plugins hook.
*/
function context_context_plugins() {
module_load_include('inc', 'context', 'context.plugins');
return _context_context_plugins();
}
/**
* Implementation of hook_context_registry().
*/
function context_context_registry() {
module_load_include('inc', 'context', 'context.plugins');
return _context_context_registry();
}
/**
* Implementation of hook_init().
*/
function context_init() {
if ($plugin = context_get_plugin('condition', 'sitewide')) {
$plugin->execute(1);
}
if ($plugin = context_get_plugin('condition', 'path')) {
$plugin->execute();
}
if ($plugin = context_get_plugin('condition', 'query_string')) {
$plugin->execute();
}
if ($plugin = context_get_plugin('condition', 'language')) {
global $language;
$plugin->execute($language->language);
}
if ($plugin = context_get_plugin('condition', 'user')) {
global $user;
$plugin->execute($user);
}
}
/**
* Implementation of hook_preprocess_menu_link().
*
* This allows menus that are not primary/secondary menus to get
* the "active" class assigned to them. This assumes they are using
* theme('menu_link') for the menu rendering to html.
*/
function context_preprocess_menu_link(&$variables) {
if($contexts = context_active_contexts()){
foreach($contexts as $context){
if((isset($context->reactions['menu']))){
if ($variables['element']['#href'] == $context->reactions['menu']) {
$variables['element']['#localized_options']['attributes']['class'][] = "active";
}
}
}
}
}
/**
* Load & crud functions ==============================================
*/
/**
* Context loader.
*
* @param $name
* The name for this context object.
*
* @return
* Returns a fully-loaded context definition.
*/
function context_load($name = NULL, $reset = FALSE) {
ctools_include('export');
static $contexts;
static $altered;
if (!isset($contexts) || $reset) {
$contexts = $altered = array();
if (!$reset && $contexts = context_cache_get('context')) {
// Nothing here.
}
else {
if ($reset) {
ctools_export_load_object_reset('context');
}
$contexts = ctools_export_load_object('context', 'all');
context_cache_set('context', $contexts);
}
}
if (isset($name)) {
// Allow other modules to alter the value just before it's returned.
if (isset($contexts[$name]) && !isset($altered[$name])) {
$altered[$name] = TRUE;
drupal_alter('context_load', $contexts[$name]);
}
return isset($contexts[$name]) ? $contexts[$name] : FALSE;
}
return $contexts;
}
/**
* Inserts or updates a context object into the database.
* @TODO: should probably return the new cid on success -- make sure
* this doesn't break any checks elsewhere.
*
* @param $context
* The context object to be inserted.
*
* @return
* Returns true on success, false on failure.
*/
function context_save($context) {
$existing = context_load($context->name, TRUE);
if ($existing && ($existing->export_type & EXPORT_IN_DATABASE)) {
drupal_write_record('context', $context, 'name');
}
else {
drupal_write_record('context', $context);
}
context_load(NULL, TRUE);
context_invalidate_cache();
return TRUE;
}
/**
* Deletes an existing context.
*
* @param $context
* The context object to be deleted.
*
* @return
* Returns true on success, false on failure.
*/
function context_delete($context) {
if (isset($context->name) && ($context->export_type & EXPORT_IN_DATABASE)) {
db_query("DELETE FROM {context} WHERE name = :name", array(':name' => $context->name));
context_invalidate_cache();
return TRUE;
}
return FALSE;
}
/**
* Exports the specified context.
*/
function context_export($context, $indent = '') {
$output = ctools_export_object('context', $context, $indent);
$translatables = array();
foreach (array('description', 'tag') as $key) {
if (!empty($context->{$key})) {
$translatables[] = $context->{$key};
}
}
$translatables = array_filter(array_unique($translatables));
if (!empty($translatables)) {
$output .= "\n";
$output .= "{$indent}// Translatables\n";
$output .= "{$indent}// Included for use with string extractors like potx.\n";
sort($translatables);
foreach ($translatables as $string) {
$output .= "{$indent}t(" . ctools_var_export($string) . ");\n";
}
}
return $output;
}
/**
* API FUNCTIONS ======================================================
*/
/**
* CTools list callback for bulk export.
*/
function context_context_list() {
$contexts = context_load(NULL, TRUE);
$list = array();
foreach ($contexts as $context) {
$list[$context->name] = $context->name;
}
return $list;
}
/**
* Wrapper around cache_get() to make it easier for context to pull different
* datastores from a single cache row.
*/
function context_cache_get($key, $reset = FALSE) {
static $cache;
if (!isset($cache) || $reset) {
$cache = cache_get('context', 'cache');
$cache = $cache ? $cache->data : array();
}
return !empty($cache[$key]) ? $cache[$key] : FALSE;
}
/**
* Wrapper around cache_set() to make it easier for context to write different
* datastores to a single cache row.
*/
function context_cache_set($key, $value) {
$cache = cache_get('context', 'cache');
$cache = $cache ? $cache->data : array();
$cache[$key] = $value;
cache_set('context', $cache);
}
/**
* Wrapper around context_load() that only returns enabled contexts.
*/
function context_enabled_contexts($reset = FALSE) {
$enabled = array();
foreach (context_load(NULL, $reset) as $context) {
if (empty($context->disabled)) {
$enabled[$context->name] = $context;
}
}
return $enabled;
}
/**
* Queue or activate contexts that have met the specified condition.
*
* @param $context
* The context object to queue or activate.
* @param $condition
* String. Name for the condition that has been met.
* @param $reset
* Reset flag for the queue static cache.
*/
function context_condition_met($context, $condition, $reset = FALSE) {
static $queue;
if (!isset($queue) || $reset) {
$queue = array();
}
if (!context_isset('context', $context->name)) {
// Context is using AND mode. Queue it.
if (isset($context->condition_mode) && $context->condition_mode == CONTEXT_CONDITION_MODE_AND) {
$queue[$context->name][$condition] = $condition;
// If all conditions have been met. set the context.
if (!array_diff(array_keys($context->conditions), $queue[$context->name])) {
context_set('context', $context->name, $context);
}
}
// Context is using OR mode. Set it.
else {
context_set('context', $context->name, $context);
}
}
}
/**
* Loads any active contexts with associated reactions. This should be run
* at a late stage of the page load to ensure that relevant contexts have been set.
*/
function context_active_contexts() {
$contexts = context_get('context');
return !empty($contexts) && is_array($contexts) ? $contexts : array();
}
/**
* Loads an associative array of conditions => context identifiers to allow
* contexts to be set by different conditions.
*/
function context_condition_map($reset = FALSE) {
static $condition_map;
if (!isset($condition_map) || $reset) {
if (!$reset && $cache = context_cache_get('condition_map')) {
$condition_map = $cache;
}
else {
$condition_map = array();
foreach (array_keys(context_conditions()) as $condition) {
if ($plugin = context_get_plugin('condition', $condition)) {
foreach (context_enabled_contexts() as $context) {
$values = $plugin->fetch_from_context($context, 'values');
foreach ($values as $value) {
if (!isset($condition_map[$condition][$value])) {
$condition_map[$condition][$value] = array();
}
$condition_map[$condition][$value][] = $context->name;
}
}
}
}
context_cache_set('condition_map', $condition_map);
}
}
return $condition_map;
}
/**
* Invalidates all context caches().
* @TODO: Update to use a CTools API function for clearing plugin caches
* when/if it becomes available.
*/
function context_invalidate_cache() {
cache_clear_all('context', 'cache', TRUE);
cache_clear_all('plugins:context', 'cache', TRUE);
}
/**
* Implementation of hook_flush_caches().
*/
function context_flush_caches() {
context_invalidate_cache();
}
/**
* Recursive helper function to determine whether an array and its
* children are entirely empty.
*/
function context_empty($element) {
$empty = TRUE;
if (is_array($element)) {
foreach ($element as $child) {
$empty = $empty && context_empty($child);
}
}
else {
$empty = $empty && !isset($element);
}
return $empty;
}
/**
* Get a plugin handler.
*/
function context_get_plugin($type = 'condition', $key, $reset = FALSE) {
static $cache = array();
if (!isset($cache[$type][$key]) || $reset) {
switch ($type) {
case 'condition':
$registry = context_conditions();
break;
case 'reaction':
$registry = context_reactions();
break;
}
if (isset($registry[$key], $registry[$key]['plugin'])) {
ctools_include('plugins');
$info = $registry[$key];
$plugins = ctools_get_plugins('context', 'plugins');
if (isset($plugins[$info['plugin']]) && $class = ctools_plugin_get_class($plugins[$info['plugin']], 'handler')) {
// Check that class exists until CTools & registry issues are resolved.
if (class_exists($class)) {
$cache[$type][$key] = new $class($key, $info);
}
}
}
}
return isset($cache[$type][$key]) ? $cache[$type][$key] : FALSE;
}
/**
* Get all context conditions.
*/
function context_conditions($reset = FALSE) {
return _context_registry('conditions', $reset);
}
/**
* Get all context reactions.
*/
function context_reactions($reset = FALSE) {
return _context_registry('reactions', $reset);
}
/**
* Retrieves & caches the context registry.
*/
function _context_registry($key = NULL, $reset = FALSE) {
static $registry;
if (!isset($registry) || $reset) {
if (!$reset && $cache = context_cache_get('registry')) {
$registry = $cache;
}
else {
$registry = module_invoke_all('context_registry');
drupal_alter('context_registry', $registry);
context_cache_set('registry', $registry);
}
}
if (isset($key)) {
return isset($registry[$key]) ? $registry[$key] : array();
}
return $registry;
}
/**
* hook_block_view_alter - if the context editor block is on this page,
* ensure that all blocks have some content so that empty blocks are
* not dropped
*/
function context_block_view_alter(&$data, $block) {
if (context_isset('context_ui', 'context_ui_editor_present') && empty($data['content'])) {
$data['content']['#markup'] = "<div class='context-block-empty-content'>" . t('This block appears empty when displayed on this page.') . "</div>";
$data['context_block_hidden'] = TRUE;
}
}
/**
* implement hook_page_alter()
*
* used for region context
*/
function context_page_alter(&$page) {
if ($plugin = context_get_plugin('reaction', 'region')) {
$plugin->execute($page);
}
}
/**
* hook_block_view_alter - if the context editor block is on this page,
* ensure that all blocks have some content so that empty blocks are
* not dropped
*/
function context_preprocess_block(&$vars) {
if (isset($vars['block']->context_block_hidden)) {
$vars['classes_array'][] = 'context-block-hidden';
$vars['classes_array'][] = 'context-block-empty';
}
}
<?php
/**
* Context registry.
*/
function _context_context_registry() {
$registry = array();
$registry['conditions'] = array(
'context' => array(
'title' => t('Context (any)'),
'description' => t('Set this context on the basis of other active contexts. Put each context on a separate line. The condition will pass if <em>any</em> of the contexts are active. You can use the <code>*</code> character (asterisk) as a wildcard and the <code>~</code> character (tilde) to prevent this context from activating if the listed context is active. Other contexts which use context conditions can not be used to exclude this context from activating.'),
'plugin' => 'context_condition_context',
),
'context_all' => array(
'title' => t('Context (all)'),
'description' => t('Set this context on the basis of other active contexts. Put each context on a separate line. The condition will pass only if <em>all</em> of the contexts are active. You can use the <code>*</code> character (asterisk) as a wildcard and the <code>~</code> character (tilde) to prevent this context from activating if the listed context is active. Other contexts which use context conditions can not be used to exclude this context from activating.'),
'plugin' => 'context_condition_context_all',
),
'node' => array(
'title' => t('Node type'),
'description' => t('Set this context when viewing a node page or using the add/edit form of one of these content types.'),
'plugin' => 'context_condition_node',
),
'sitewide' => array(
'title' => t('Sitewide context'),
'description' => t('Should this context always be set? If <strong>true</strong>, this context will be active across your entire site.'),
'plugin' => 'context_condition_sitewide',
),
'default' => array(
'title' => t('Default context'),
'description' => t('This context will be set if no other context is active except sitewide contexts.'),
'plugin' => 'context_condition_default',
),
'path' => array(
'title' => t('Path'),
'description' => t('Set this context when any of the paths above match the page path. Put each path on a separate line. You can use the <code>*</code> character (asterisk) as a wildcard and the <code>~</code> character (tilde) to exclude one or more paths. Use &lt;front&gt; for the site front page.'),
'plugin' => 'context_condition_path',
),
'query_string' => array(
'title' => t('Query String'),
'description' => t('Set this context when any of the query strings above match the page query string. Put each query string on a separate line. You can use the "*" character as a wildcard and <code>~</code> to exclude one or more query strings.'),
'plugin' => 'context_condition_query_string',
),
'user' => array(
'title' => t('User role'),
'description' => t('Set this context when the current user has one of the selected role(s).'),
'plugin' => 'context_condition_user',
),
'user_page' => array(
'title' => t('User page'),
'description' => t('Set this context when viewing a user page.'),
'plugin' => 'context_condition_user_page',
),
);
if (module_exists('menu')) {
$registry['conditions']['menu'] = array(
'title' => t('Menu'),
'description' => t('Set this context when any of the selected menu items belong to the current active menu trail.'),
'plugin' => 'context_condition_menu',
);
}
if (module_exists('views')) {
$registry['conditions']['views'] = array(
'title' => t('Views'),
'description' => t('Set this context when displaying the page of one of these views.'),
'plugin' => 'context_condition_views',
);
}
if (module_exists('book')) {
$registry['conditions']['book'] = array(
'title' => t('Book'),
'description' => t('Set this context when a node in the selected book is viewed.'),
'plugin' => 'context_condition_book',
);
$registry['conditions']['bookroot'] = array(
'title' => t('Book root'),
'description' => t('Set this context when viewing a node whose root book is of the selected type.'),
'plugin' => 'context_condition_bookroot',
);
}
if (module_exists('locale')) {
$registry['conditions']['language'] = array(
'title' => t('Language'),
'description' => t('Set this context when viewing the site in the selected language.'),
'plugin' => 'context_condition_language',
);
}
if (module_exists('taxonomy')) {
$registry['conditions']['node_taxonomy'] = array(
'title' => t('Taxonomy'),
'description' => t('Set this context when viewing a node with the selected taxonomy terms.'),
'plugin' => 'context_condition_node_taxonomy',
);
$registry['conditions']['taxonomy_term'] = array(
'title' => t('Taxonomy term'),
'description' => t('Set this context when viewing a taxonomy term page.'),
'plugin' => 'context_condition_taxonomy_term',
);
}
$registry['reactions'] = array(
'block' => array(
'title' => t('Blocks'),
'description' => t('Control block visibility using context.'),
'plugin' => 'context_reaction_block',
),
'region' => array(
'title' => t('Regions'),
'description' => t('Control Region visiblity using context.'),
'plugin' => 'context_reaction_region',
),
'breadcrumb' => array(
'title' => t('Breadcrumb'),
'description' => t('Set the breadcrumb trail to the selected menu item.'),
'plugin' => 'context_reaction_breadcrumb',
),
'template_suggestions' => array(
'title' => t('Template suggestions'),
'description' => t('Add template suggestions using context.'),
'plugin' => 'context_reaction_template_suggestions',
),
'theme' => array(
'title' => t('Theme Page'),
'description' => t('Control page theme variables using context.'),
'plugin' => 'context_reaction_theme',
),
'theme_html' => array(
'title' => t('Theme HTML'),
'description' => t('Control HTML theme variables using context.'),
'plugin' => 'context_reaction_theme_html',
),
'debug' => array(
'title' => t('Debug'),
'description' => t('Debug output reaction for SimpleTest.'),
'plugin' => 'context_reaction_debug',
),
);
if (module_exists('menu')) {
$registry['reactions']['menu'] = array(
'title' => t('Menu'),
'description' => t('Control menu active class using context.'),
'plugin' => 'context_reaction_menu',
);
}
if (module_exists('css_injector')) {
$registry['reactions']['css_injector'] = array(
'title' => t('CSS Injector'),
'description' => t('Inject the selected css when this context is set.'),
'plugin' => 'context_reaction_css_injector',
);
}
return $registry;
}
/**
* Context plugins.
*/
function _context_context_plugins() {
$plugins = array();
/**
* Conditions.
*/
$plugins['context_condition'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition.inc',
'class' => 'context_condition',
),
);
$plugins['context_condition_context'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_context.inc',
'class' => 'context_condition_context',
'parent' => 'context_condition_path',
),
);
$plugins['context_condition_context_all'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_context_all.inc',
'class' => 'context_condition_context_all',
'parent' => 'context_condition_path',
),
);
$plugins['context_condition_node'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_node.inc',
'class' => 'context_condition_node',
'parent' => 'context_condition',
),
);
$plugins['context_condition_sitewide'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_sitewide.inc',
'class' => 'context_condition_sitewide',
'parent' => 'context_condition',
),
);
$plugins['context_condition_default'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_default.inc',
'class' => 'context_condition_default',
'parent' => 'context_condition',
),
);
$plugins['context_condition_path'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_path.inc',
'class' => 'context_condition_path',
'parent' => 'context_condition',
),
);
$plugins['context_condition_query_string'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') .'/plugins',
'file' => 'context_condition_query_string.inc',
'class' => 'context_condition_query_string',
'parent' => 'context_condition_path',
),
);
$plugins['context_condition_user'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_user.inc',
'class' => 'context_condition_user',
'parent' => 'context_condition',
),
);
$plugins['context_condition_user_page'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_user_page.inc',
'class' => 'context_condition_user_page',
'parent' => 'context_condition',
),
);
$plugins['context_condition_menu'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_menu.inc',
'class' => 'context_condition_menu',
'parent' => 'context_condition',
),
);
if (module_exists('taxonomy')) {
$plugins['context_condition_node_taxonomy'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_node_taxonomy.inc',
'class' => 'context_condition_node_taxonomy',
'parent' => 'context_condition_node',
),
);
$plugins['context_condition_taxonomy_term'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_taxonomy_term.inc',
'class' => 'context_condition_taxonomy_term',
'parent' => 'context_condition',
),
);
}
if (module_exists('locale')) {
$plugins['context_condition_language'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_language.inc',
'class' => 'context_condition_language',
'parent' => 'context_condition',
),
);
}
if (module_exists('book')) {
$plugins['context_condition_book'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_book.inc',
'class' => 'context_condition_book',
'parent' => 'context_condition',
),
);
$plugins['context_condition_bookroot'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_bookroot.inc',
'class' => 'context_condition_bookroot',
'parent' => 'context_condition_node',
),
);
}
if (module_exists('views')) {
$plugins['context_condition_views'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_condition_views.inc',
'class' => 'context_condition_views',
'parent' => 'context_condition',
),
);
}
/**
* Reactions.
*/
$plugins['context_reaction'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction.inc',
'class' => 'context_reaction',
),
);
$plugins['context_reaction_block'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction_block.inc',
'class' => 'context_reaction_block',
'parent' => 'context_reaction',
),
);
$plugins['context_reaction_region'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction_region.inc',
'class' => 'context_reaction_region',
'parent' => 'context_reaction',
),
);
$plugins['context_reaction_breadcrumb'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction_breadcrumb.inc',
'class' => 'context_reaction_breadcrumb',
'parent' => 'context_reaction_menu',
),
);
$plugins['context_reaction_template_suggestions'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction_template_suggestions.inc',
'class' => 'context_reaction_template_suggestions',
'parent' => 'context_reaction',
),
);
$plugins['context_reaction_menu'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction_menu.inc',
'class' => 'context_reaction_menu',
'parent' => 'context_reaction',
),
);
$plugins['context_reaction_theme'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction_theme.inc',
'class' => 'context_reaction_theme',
'parent' => 'context_reaction',
),
);
$plugins['context_reaction_theme_html'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction_theme_html.inc',
'class' => 'context_reaction_theme_html',
'parent' => 'context_reaction_theme',
),
);
$plugins['context_reaction_debug'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction_debug.inc',
'class' => 'context_reaction_debug',
'parent' => 'context_reaction',
),
);
if (module_exists('css_injector')) {
$plugins['context_reaction_css_injector'] = array(
'handler' => array(
'path' => drupal_get_path('module', 'context') . '/plugins',
'file' => 'context_reaction_css_injector.inc',
'class' => 'context_reaction_css_injector',
'parent' => 'context_reaction',
),
);
}
return $plugins;
}
Context layouts
---------------
Context layouts provides a formalized way for themes to declare and switch
between page templates using Context. It is a continuation of an old Drupal
themer's trick to switch to something besides the standard `page.tpl.php` file
for a variety of special-case pages like the site frontpage, login page, admin
section, etc.
Requirements
------------
In order to use context layouts, your site must meet a few conditions:
- Context and Context layouts modules are enabled (`admin/modules`).
- You are using a theme which provides and has declared multiple layouts. (See
"Example themes" for themes you can try.)
Basic usage
-----------
Once you have layouts enabled, you can have a context trigger the usage of a
particular layout in either the admin interface (`admin/structure/context`) or
inline context editor. Different layouts may have fewer or greater regions than
the default page template, so adjust your blocks accordingly.
Supporting context layouts in your theme
----------------------------------------
You can add layouts support to your theme by declaring additional layouts in
your theme's info file. Here is an example:
`example.info`
name = "Example"
description = "Example theme"
core = "6.x"
engine = "phptemplate"
regions[left] = "Left sidebar"
regions[right] = "Right sidebar"
regions[content] = "Content"
regions[footer] = "Footer"
; Layout: Default
layouts[default][name] = "Default"
layouts[default][description] = "Simple two column page."
layouts[default][template] = "page"
layouts[default][regions][] = "content"
layouts[default][regions][] = "right"
; Layout: Columns
layouts[columns][name] = "3 columns"
layouts[columns][description] = "Three column page."
layouts[columns][stylesheet] = "layout-columns.css"
layouts[columns][template] = "layout-columns"
layouts[columns][regions][] = "left"
layouts[columns][regions][] = "content"
layouts[columns][regions][] = "right"
layouts[columns][regions][] = "footer"
Each layout is declared under `layouts` with the key as the identifier that will
be used by context for this layout. You may use any reasonable machine name for
each layout, but note that `default` is special -- it will be the default layout
for your theme if no other layout is specified.
The following keys can be declared for each layout:
- `name`: The human readable name for this layout, shown in the admin UI.
- `description`: A short description of your layout, same as above.
- `stylesheet`: A stylesheet to be included with the layout. Optional.
- `template`: The name of the template file for this layout, without the
`.tpl.php` extension.
- `region`: An array of regions supported by this layout. Note that any of the
regions listed here **must also be declared** in the standard theme `regions`
array.
Example themes
--------------
- Cube, a subtheme included with [Rubik][1] provides a variety of layouts.
- [Ginkgo][2] the default theme included with Open Atrium.
[1]: http://github.com/developmentseed/rubik/downloads
[2]: http://github.com/developmentseed/ginkgo/downloads
name = Context layouts
description = Allow theme layer to provide multiple region layouts and integrate with context.
dependencies[] = context
package = Context
core = 7.x
files[] = plugins/context_layouts_reaction_block.inc
<?php
/**
* Implementation of hook_help().
*/
function context_layouts_help($path, $arg) {
switch ($path) {
case 'admin/help#context_layouts':
$output = file_get_contents(drupal_get_path('module', 'context_layouts') .'/README.txt');
return module_exists('markdown') ? filter_xss_admin(module_invoke('markdown', 'filter', 'process', 0, -1, $output)) : '<pre>'. check_plain($output) .'</pre>';
}
}
/**
* Implementation of hook_context_plugins().
* This is a ctools plugins hook.
*/
function context_layouts_context_plugins() {
return array(
'context_layouts_reaction_block' => array(
'handler' => array(
'path' => drupal_get_path('module', 'context_layouts') .'/plugins',
'file' => 'context_layouts_reaction_block.inc',
'class' => 'context_layouts_reaction_block',
'parent' => 'context_reaction_block',
),
),
);
}
/**
* Implementation of hook_context_registry_alter().
*/
function context_layouts_context_registry_alter(&$registry) {
if (isset($registry['reactions']['block'])) {
$registry['reactions']['block']['plugin'] = 'context_layouts_reaction_block';
}
}
/**
* Implementation of hook_theme().
* Declares each theme's layouts as a page template suggestion.
*/
function context_layouts_theme() {
$info = array();
foreach (list_themes() as $theme) {
if (!empty($theme->status) && $layouts = context_layouts_get_layouts($theme->name)) {
foreach ($layouts as $layout) {
if (!empty($layout['template'])) {
$info["page__context_layouts_{$theme->name}_{$layout['layout']}"] = array(
'template' => $layout['template'],
'path' => $layout['path'],
);
}
}
}
}
return $info;
}
/**
* Implementation of hook_context_page_reaction().
*/
function context_layouts_context_page_reaction() {
$plugin = context_get_plugin('reaction', 'block');
if ($plugin && method_exists($plugin, 'add_layout_stylesheet')) {
$plugin->add_layout_stylesheet();
}
}
/**
* Preprocessor for theme('page').
*/
function context_layouts_preprocess_page(&$vars) {
$plugin = context_get_plugin('reaction', 'block');
if ($plugin && method_exists($plugin, 'add_layout_template')) {
$plugin->add_layout_template($vars);
}
}
/**
* Retrieve layouts for the specified theme.
*/
function context_layouts_get_layouts($theme = NULL, $reset = FALSE) {
static $layouts = array();
$layouts = $reset ? array() : $layouts;
global $theme_key;
$theme = isset($theme) ? $theme : $theme_key;
if (!isset($layouts[$theme])) {
$info = system_get_info('theme', $theme);
$themes = array();
// Find all our ancestor themes that use layouts.
if (isset($info['base theme'])) {
while (!empty($info['base theme'])) {
$base_theme = $info['base theme'];
$info = system_get_info('theme', $base_theme);
$themes[$base_theme] = $info;
}
}
// Assemble in inheritance order and add the theme on.
$themes = array_reverse($themes);
$themes[$theme] = system_get_info('theme', $theme);
// Merge layout info into a single array.
foreach ($themes as $key => $info) {
$path = drupal_get_path('theme', $key);
if (!empty($info['layouts'])) {
foreach ($info['layouts'] as $layout => $layout_info) {
$layout_info['layout'] = str_replace('-', '_', $layout);
$layout_info['theme'] = $key;
$layout_info['path'] = $path;
$layouts[$theme][$layout] = $layout_info;
}
}
}
}
return isset($layouts[$theme]) ? $layouts[$theme] : FALSE;
}
/**
* Get the active layout for the current page.
*/
function context_layouts_get_active_layout($info = TRUE) {
$plugin = context_get_plugin('reaction', 'block');
if ($plugin && method_exists($plugin, 'get_active_layout')) {
return $plugin->get_active_layout($info);
}
}
#admin-toolbar div.context-editor-block-layouts {
padding:0px 0px 9px;
border-bottom:1px solid #333;
margin:0px 0px 10px;
}
#admin-toolbar div.context-editor-block-layouts div.form-item { display:inline; }
#admin-toolbar div.context-editor-block-layouts select { width:50%; }
<?php
class context_layouts_reaction_block extends context_reaction_block {
/**
* Override of is_enabled_region().
* Check that there is an active layout and it supports the given region.
*/
protected function is_enabled_region($region) {
$layout = $this->get_active_layout();
if ($layout && isset($layout['regions']) && is_array($layout['regions'])) {
return in_array($region, $layout['regions'], TRUE) && parent::is_enabled_region($region);
}
return parent::is_enabled_region($region);
}
/**
* Retrieve the first layout specified found by any active contexts.
*/
function get_active_layout($info = TRUE) {
$contexts = $this->get_contexts();
$layouts = context_layouts_get_layouts();
if (!empty($contexts) && !empty($layouts)) {
foreach ($contexts as $context) {
$values = $this->fetch_from_context($context);
if (isset($values['layout']) && isset($layouts[$values['layout']])) {
return $info ? $layouts[$values['layout']] : $values['layout'];
}
}
}
// Fallback to default layout if provided.
if (isset($layouts['default'])) {
return $info ? $layouts['default'] : 'default';
}
return FALSE;
}
/**
* Add the layout template to page vars.
*/
function add_layout_template(&$vars) {
if ($layout = $this->get_active_layout()) {
if (!empty($layout['template'])) {
global $theme;
$vars['theme_hook_suggestion'] = "page__context_layouts_{$theme}_{$layout['layout']}";
}
}
}
/**
* Add the layout stylesheet to the CSS.
*/
function add_layout_stylesheet() {
if ($layout = $this->get_active_layout()) {
if (!empty($layout['stylesheet'])) {
drupal_add_css(drupal_get_path('theme', $layout['theme']) . '/' . $layout['stylesheet']);
}
}
}
/**
* Override of editor form.
*/
function editor_form($context) {
drupal_add_css(drupal_get_path('module', 'context_layouts') . '/plugins/context_layouts_reaction_block.css');
$form = parent::editor_form($context);
if ($layouts = $this->get_layout_options()) {
$options = $this->fetch_from_context($context);
$form['layout'] = array(
// #tree *must* be true for our values to be nested correctly.
'#tree' => TRUE,
'#prefix' => '<div class="context-editor-block-layouts">',
'#suffix' => '</div>',
'#weight' => -100,
'layout' => array(
'#title' => t('Layout'),
'#options' => $layouts,
'#type' => 'select',
'#weight' => -100,
'#default_value' => isset($options['layout']) ? $options['layout'] : NULL,
'#required' => FALSE,
'#empty_value' => 0,
'#empty_option' => '- ' . t('Site default') . ' -',
),
'update' => array(
'#value' => t('Change layout'),
'#type' => 'submit',
),
);
}
return $form;
}
/**
* Override of editor form submit.
*/
function editor_form_submit(&$context, $values) {
// Someone has changed the layout, assume that the block values are not actually usable here.
if (isset($context->reactions['block']['layout']) && $context->reactions['block']['layout'] != $values['layout']['layout']) {
$options = $context->reactions['block'];
}
else {
$options = parent::editor_form_submit($context, $values);
}
if (!empty($values['layout']['layout'])) {
$options['layout'] = $values['layout']['layout'];
}
else {
unset($options['layout']);
}
return $options;
}
/**
* Override of options form.
*/
function options_form($context) {
$form = parent::options_form($context);
$options = $this->fetch_from_context($context);
// Only alter the options form if the theme provides layouts.
$theme_key = variable_get('theme_default', 'garland');
$layouts = $this->get_layout_options();
if (!empty($layouts)) {
$form['layout'] = array(
'#title' => t('Layout'),
'#description' => t('Choose one of the layouts provided by the default theme.'),
'#options' => $layouts,
'#type' => 'select',
'#weight' => -100,
'#default_value' => !empty($options['layout']) ? $options['layout'] : NULL,
'#attributes' => array('class' => array('context-blockform-layout')),
'#required' => FALSE,
'#empty_value' => 0,
'#empty_option' => '- ' . t('Site default') . ' -',
);
// Add js.
// @TODO: Move this to a theme function or somewhere that will get called even
// if the form is using a cached version of itself (e.g. when validate fails).
drupal_add_js(drupal_get_path('module', 'context_layouts') . '/plugins/context_layouts_reaction_block.js');
drupal_add_js(array('contextLayouts' => array('layouts' => $this->get_layout_regions())), 'setting');
}
return $form;
}
/**
* Override of submit handler.
*/
function options_form_submit($values) {
$options = parent::options_form_submit($values);
// Only alter the options form if the theme provides layouts.
$theme_key = variable_get('theme_default', 'garland');
$layouts = context_layouts_get_layouts($theme_key);
// Check that this is a valid layout.
if (!empty($values['layout']) && isset($layouts[$values['layout']])) {
$layout = $values['layout'];
$options['layout'] = $layout;
// Remove blocks that don't belong to regions in this layout.
if (isset($layouts[$layout]['regions'])) {
foreach ($options['blocks'] as $bid => $block) {
if (!in_array($block['region'], $layouts[$layout]['regions'])) {
unset($options['blocks'][$bid]);
}
}
}
}
return $options;
}
/**
* Get layout options for the given theme.
*/
protected function get_layout_options($theme_key = NULL) {
$theme_key = !isset($theme_key) ? variable_get('theme_default', 'garland') : $theme_key;
$layouts = context_layouts_get_layouts($theme_key);
$layout_options = array();
if (!empty($layouts)) {
foreach ($layouts as $layout => $info) {
$layout_options[$layout] = isset($info['name']) ? $info['name'] : $layout_options;
}
}
return $layout_options;
}
/**
* Get a layout to region map for the given theme.
*/
protected function get_layout_regions($theme_key = NULL) {
$theme_key = !isset($theme_key) ? variable_get('theme_default', 'garland') : $theme_key;
$layouts = context_layouts_get_layouts($theme_key);
if (!empty($layouts)) {
$layout_regions = array();
foreach ($layouts as $layout => $info) {
$layout_regions[$layout] = is_array($info['regions']) ? $info['regions'] : array();
}
}
return $layout_regions;
}
}
(function($) {
Drupal.behaviors.contextLayoutsReactionBlock = {};
Drupal.behaviors.contextLayoutsReactionBlock.attach = function(context) {
// ContextBlockForm: Init.
$('.context-blockform-layout:not(.contextLayoutsProcessed)').each(function() {
$(this).addClass('contextLayoutsProcessed');
$(this).change(function() {
var layout = $(this).val();
if (Drupal.settings.contextLayouts.layouts[layout]) {
$('#context-blockform td.blocks').find('table, div.label, div.tabledrag-toggle-weight-wrapper').hide();
for (var key in Drupal.settings.contextLayouts.layouts[layout]) {
var region = Drupal.settings.contextLayouts.layouts[layout][key];
$('.context-blockform-regionlabel-'+region).show().next('div.tabledrag-toggle-weight-wrapper').show();
$('#context-blockform-region-'+region).show();
}
if (Drupal.contextBlockForm) {
Drupal.contextBlockForm.setState();
}
}
});
$(this).change();
});
};
})(jQuery);
\ No newline at end of file
Context UI
----------
Context UI provides an administrative interface for managing and editing
Contexts. It is not necessary for the proper functioning of contexts once they
are built and can be turned off on most production sites.
Requirements
------------
- Context, Context UI modules enabled (`admin/modules`)
Basic usage
-----------
As a site administrator you can manage your site's contexts at
`admin/structure/context`. The main page will show you a list of the contexts
on the site and give you some options for managing each context.
When editing or adding a new context, you will be presented with a form to
manage some basic information about the context and then alter its conditions
and reactions.
- `name`: The name of your context. This is the main identifier for your context
and cannot be changed after you've created it.
- `description`: A description or human-readable name for your context. This is
displayed in the inline editor if available instead of the name.
- `tag`: A category for organizing contexts in the administrative context
listing. Optional.
**Conditions**
When certain conditions are true, your context will be made active. You can
customize the conditions that trigger the activation of your context.
- **Condition mode**: you can choose to have your context triggered if **ANY**
conditions are met or only active when **ALL** conditions are met.
- **Adding/removing conditions**: you can add or remove to the conditions on
your context using the conditions dropdown.
- **Individual settings**: most conditions provide a simple form for selecting
individual settings for that condition. For example, the node type condition
allows you to choose which node types activate the context.
**Reactions**
Whenever a particular context is active, all of its reactions will be run.
Like conditions, reactions can be added or removed and have settings that can
be configured.
- **Reaction Block Groupings**: You can influence what "group" a block appears
in when listing all blocks available to be added to a region. This is done
by specifying $block->context_group via hook_block_info. If no group is
specified it will default to the module name, but if a group is specified
it will be grouped under that group name.
Using the inline editor
-----------------------
The inline editor allows you to manage the block reaction for active
contexts within the context of a page rather than through the admin
interface. This can also be helpful when managing block ordering among
multiple contexts.
1. As an administrative user go to `admin/structure/context/settings`.
2. Check the 'Use Context Editor Dialog' block and save. You should also
check the show all regions box.
3. When viewing a page with one or more active contexts, you will see
the option to configure layout in the contextual links on all blocks
on the page. This will allow you to manage the blocks placed by the
block reaction for contexts.
4. You can use the context editor to adjust the conditions under which each
context is active and alter its reactions.
/**
* Editor =============================================================
*/
div.context-editor div.label {
float:left;
font-size: 14px;
}
div.context-editor div.links { float:right; }
div.context-editor div.bottom {
font-size: 12px;
font-style: italic;
font-weight:normal;
color: #999;
}
div.context-editor div.context-editable { display:none; }
div.context-editor div.links a.done { display:none; }
div.context-editor li.context-editing a.edit { display:none; }
div.context-editor li.context-editing a.done { display:block; }
/* Don't display form submission buttons initially or when editing */
body.context-editing div.context-editor div.links { display:none; }
body.context-editing div.context-editor li.context-editing div.links { display:block; }
div.context-editor div.buttons { display:none; }
form.edited div.context-editor div.buttons { display:block; }
body.context-editing form.edited div.context-editor div.buttons { display:none; }
/**
* Styles for visual integration with admin.
*/
#admin-toolbar div.context-editor div.links a:hover {
background:#eee;
color:#000;
}
#admin-toolbar div.context-editor div.links a {
float:left;
padding:0px 10px;
margin-right:5px;
background:#222;
font-size:11px;
-moz-border-radius:10px;
-webkit-border-radius:10px;
}
div.context-editor div.context-editable { padding:5px 0px; }
#admin-toolbar div.context-editor div.buttons {
padding:10px 0px;
text-align:center;
background:#111;
}
/**
* Horizontal
*/
#admin-toolbar.horizontal form.edited div.context-editor div.buttons,
#admin-toolbar.horizontal div.context-editor div.item-list {
float:left;
clear:left;
width:30%;
}
#admin-toolbar.horizontal div.context-editor div.contexts {
width:69.9%;
float:right;
}
#admin-toolbar.horizontal div.context-editor div.context-editable { padding-left:20px }
/**
* Admin listing page =================================================
*/
table.context-admin td.tag { font-style:italic; }
table.context-admin td.ctools-export-ui-name {
width:75%;
padding-left:20px;
}
table.context-admin td.ctools-export-ui-operations { white-space:nowrap; }
table.context-admin td.ctools-export-ui-storage { color:#999; }
table.context-admin div.description {
padding-left:10px;
margin:0px;
}
table.context-admin input.form-text { width:90%; }
/**
* Context form =======================================================
*/
.context-plugins {
position:relative;
margin:0px 0px 10px;
}
.context-plugins .context-plugin-info {
padding:10px 10px 9px;
border-bottom:1px solid #e8e8e8;
}
.context-plugins .context-plugin-info div.description {
margin:0px 0px 10px;
padding:0px;
}
.context-plugins .context-plugin-selector {
width:25%;
background:#fff;
}
.context-plugins .context-plugin-list .disabled { display:none; }
.context-plugins .context-plugin-list ul {
margin:0px;
padding:0px;
}
.context-plugins .context-plugin-list li {
list-style:none;
list-style-image:none;
background:transparent;
padding:0px;
margin:0px;
border:0px;
}
.context-plugins .context-plugin-list li a {
display:block;
position:relative;
padding:5px 10px 4px;
border-bottom:1px solid #e8e8e8;
}
.context-plugins .context-plugin-list li a.active-form {
background:#f8f8f8;
color:#333;
font-weight:bold;
}
.context-plugins .context-plugin-list li span.remove {
display:none;
position:absolute;
top:5px;
right:10px;
font-size:9px;
font-weight:normal;
-moz-border-radius:5px;
-webkit-border-radius:5px;
padding:0px 5px;
background:#fff;
}
.context-plugins .context-plugin-list li a:hover span.remove { display:block; }
.context-plugins .context-plugin-forms {
float:right;
width:75%;
background:#f8f8f8;
min-height:200px;
}
.context-plugins .context-plugin-forms .context-plugin-form {
padding:10px;
display:none;
}
.context-plugins .context-plugin-forms .active-form { display:block; }
.context-plugins .context-plugin-form .form-checkboxes {
max-height:300px;
overflow:auto;
}
name = Context UI
description = "Provides a simple UI for settings up a site structure using Context."
dependencies[] = context
package = Context
core = "7.x"
configure = admin/structure/context
files[] = context.module
files[] = tests/context_ui.test
<?php
/**
* Update 6004: Placeholder update to ensure migrations from older versions
* in Aegir do not fail.
*/
function context_ui_update_6004() {
return array();
}
(function($) {
/**
* Context plugin form.
*/
function DrupalContextPlugins(form) {
this.form = form;
// Sync the form selector and state field with the list of plugins currently enabled.
this.setState = function() {
var state = [];
$('.context-plugin-list > li', this.form).each(function() {
var plugin = $(this).attr('class').split('context-plugin-')[1].split(' ')[0];
if ($(this).is('.disabled')) {
$('.context-plugin-selector select option[value='+plugin+']', this.form).show();
}
else {
state.push(plugin);
$('.context-plugin-selector select option[value='+plugin+']', this.form).hide();
}
});
// Set the hidden plugin list state.
$('.context-plugin-selector input.context-plugins-state', this.form).val(state.join(','));
// Reset the selector.
$('.context-plugin-selector select', this.form).val(0);
return this;
};
// Add a plugin to the list.
this.addPlugin = function(plugin) {
$('.context-plugin-list > li.context-plugin-'+plugin, this.form).removeClass('disabled');
this.showForm(plugin).setState();
return this;
};
// Remove a plugin from the list.
this.removePlugin = function(plugin) {
$('.context-plugin-list > li.context-plugin-'+plugin, this.form).addClass('disabled');
this.hideForm(plugin).setState();
return this;
};
// Show a plugin form.
this.showForm = function(plugin) {
$('.context-plugin-forms > .context-plugin-form.active-form', this.form).removeClass('active-form');
$('.context-plugin-forms > .context-plugin-form-'+plugin, this.form).addClass('active-form');
$('.context-plugin-list > li > a').removeClass('active-form');
$('.context-plugin-list > li.context-plugin-'+plugin+' > a').addClass('active-form');
return this;
};
// Show a plugin form.
this.hideForm = function(plugin) {
$('.context-plugin-forms > .context-plugin-form-'+plugin, this.form).removeClass('active-form');
$('.context-plugin-list > li.context-plugin-'+plugin+' > a').removeClass('active-form');
return this;
};
// Select handler.
$('.context-plugin-selector select', this.form).change(function() {
var plugins = $(this).parents('div.context-plugins').data('contextPlugins');
if (plugins) {
var plugin = $(this).val();
plugins.addPlugin(plugin);
}
});
// Show form handler.
$('.context-plugin-list > li > a', this.form).click(function() {
var plugins = $(this).parents('div.context-plugins').data('contextPlugins');
if (plugins) {
var plugin = $(this).attr('href').split('#context-plugin-form-')[1];
plugins.showForm(plugin);
}
return false;
});
// Remove handler.
$('.context-plugin-list span.remove', this.form).click(function() {
var plugins = $(this).parents('div.context-plugins').data('contextPlugins');
if (plugins) {
var plugin = $(this).parent().attr('href').split('#context-plugin-form-')[1];
plugins.removePlugin(plugin);
}
return false;
});
// Set the plugin states.
this.setState();
}
Drupal.behaviors.context_ui = { attach: function(context) {
// Initialize context plugin form.
$('form div.context-plugins:not(.context-ui-processed)').each(function() {
$(this).addClass('context-ui-processed');
$(this).data('contextPlugins', new DrupalContextPlugins($(this)));
});
// Initialize context editor.
if ($().pageEditor) {
$('form.context-editor:not(.context-ui-processed)')
.addClass('context-ui-processed')
.pageEditor()
.each(function() {
var editor = $(this);
var defaultContext = $('li.context-editable', this).attr('id').split('context-editable-trigger-')[1];
$(this).data('defaultContext', defaultContext);
// Attach start/end handlers to editable contexts.
$('li.context-editable a.edit', editor).click(function() {
var trigger = $(this).parents('li.context-editable').addClass('context-editing');
var context = trigger.attr('id').split('context-editable-trigger-')[1];
editor.pageEditor('start', context);
return false;
});
$('li.context-editable a.done', editor).click(function() {
editor.pageEditor('end');
return false;
});
$(editor).submit(function() {
if (editor.pageEditor('isEditing')) {
editor.pageEditor('end');
}
});
// Handler for start event.
editor.bind('start.pageEditor', function(event, context) {
// Fallback to first context if param is empty.
if (!context) {
context = $(this).data('defaultContext');
$('li#context-editable-trigger-'+context, this).addClass('context-editing');
}
$(document.body).addClass('context-editing');
$('#context-editable-'+context, this).show();
});
// Handler for end event.
editor.bind('end.pageEditor', function(event, context) {
$(document.body).removeClass('context-editing');
$('div.contexts div.context-editable', this).hide();
$('li.context-editable').removeClass('context-editing');
$('form.context-editor').addClass('edited');
});
});
}
}};
})(jQuery);
<?php
/**
* Implementation of hook_ctools_plugin_directory().
*/
function context_ui_ctools_plugin_directory($module, $plugin) {
if ($module == 'ctools' && $plugin == 'export_ui') {
return 'export_ui';
}
}
/**
* Implementation of hook_theme().
*/
function context_ui_theme() {
$items = array();
$items['context_ui_form'] = array(
'render element' => 'form',
'path' => drupal_get_path('module', 'context_ui') .'/theme',
'template' => 'context-ui-form',
'file' => 'theme.inc',
);
$items['context_ui_plugins'] = array(
'render element' => 'form',
'path' => drupal_get_path('module', 'context_ui') .'/theme',
'template' => 'context-ui-plugins',
'file' => 'theme.inc',
);
$items['context_ui_editor'] = array(
'render element' => 'form',
'path' => drupal_get_path('module', 'context_ui') .'/theme',
'template' => 'context-ui-editor',
'file' => 'theme.inc',
);
return $items;
}
/**
* Implementation of hook_block_info().
*/
function context_ui_block_info() {
$blocks = array();
$blocks['editor'] = array('info' => t('Context editor'), 'admin' => TRUE);
if (module_exists('devel')) {
$blocks['devel'] = array('info' => t('Context inspector'), 'admin' => TRUE);
}
return $blocks;
}
/**
* Implementation of hook_block_view().
*/
function context_ui_block_view($delta = '') {
switch ($delta) {
case 'editor':
if (user_access('administer contexts') && strpos($_GET['q'], 'admin/structure/context') === FALSE && $contexts = context_active_contexts()) {
return array(
'subject' => t('Context editor'),
'content' => drupal_get_form('context_ui_editor', $contexts),
);
}
break;
case 'devel':
if (module_exists('devel') && $all = context_get()) {
return array(
'subject' => t('Context inspector'),
'content' => kdevel_print_object($all),
);
}
break;
}
}
/**
* Implementation of hook_permission().
*/
function context_ui_permission() {
$permissions = array();
$permissions['administer contexts'] = array(
'title' => 'Administer contexts',
'description' => 'Associate menus, views, blocks, etc. with different contexts to structure your site.'
);
$permissions['context ajax block access'] = array(
'title' => t('Access All Blocks'),
'description' => t('Allows users to access all rendered blocks via an AJAX callback. If you have some blocks that should not be rendered for some users but need those users to be able to use context UI, then implement hook_context_allow_ajax_block_access with the necessary logic.'),
);
return $permissions;
}
/**
* Implementation of hook_menu().
*/
function context_ui_menu() {
$items = array();
$items['admin/structure/context/settings'] = array(
'title' => 'Settings',
'access callback' => 'user_access',
'access arguments' => array('administer contexts'),
'page callback' => 'drupal_get_form',
'page arguments' => array('context_ui_settings'),
'type' => MENU_LOCAL_TASK,
'weight' => 3,
);
$items['context-ui/activate'] = array(
'title' => 'Activate Context UI',
'access arguments' => array('administer contexts'),
'page callback' => 'context_ui_activate',
'type' => MENU_CALLBACK
);
$items['context-ui/deactivate'] = array(
'title' => 'Deactivate Context UI',
'access arguments' => array('administer contexts'),
'page callback' => 'context_ui_deactivate',
'type' => MENU_CALLBACK
);
return $items;
}
/**
* Implementation of hook_help().
*/
function context_ui_help($path, $arg) {
switch ($path) {
case 'admin/help#context_ui':
$output = file_get_contents(drupal_get_path('module', 'context_ui') .'/README.txt');
return module_exists('markdown') ? filter_xss_admin(module_invoke('markdown', 'filter', 'process', 0, -1, $output)) : '<pre>'. check_plain($output) .'</pre>';
case 'admin/structure/context':
return '<p>'. t('Context allows you to manage contextual conditions and reactions for different portions of your site. You can think of each context as representing a "section" of your site. For each context, you can choose the conditions that trigger this context to be active and choose different aspects of Drupal that should react to this active context.') .'</p>';
}
}
/**
* Inline context editor form.
*/
function context_ui_editor($form, &$form_state, $contexts) {
$form = array(
'#attributes' => array('class' => array('context-editor')),
'#theme' => array('context_ui_editor'),
'editables' => array(),
'contexts' => array('#tree' => TRUE),
'buttons' => array('#tree' => FALSE),
);
$form['title'] = array(
'#prefix' => '<h2 class="context-editor-title">',
'#markup' => t('Select the Context/Layer to Edit'),
'#suffix' => '</h2>',
'#weight' => -2,
);
//add some help text to the top of the form
$form['help'] = array (
'#prefix' => '<p class="context-help help">',
'#markup' => t('Select which context, or layer of blocks, to edit.
Each context is configured to appear on different sets of pages so read the description carefully.
When you are done editing click Done and save your changes.
You may use the Stop Editing Layout link to close the editor.'),
'#suffix' => '</p>',
'#weight' => -1,
);
$items = array();
$form_context = array();
ksort($contexts);
foreach ($contexts as $context) {
$edit = l(t('Edit'), $_GET['q'], array('fragment' => $context->name, 'attributes' => array('class' => array('edit'))));
$done = l(t('Done'), $_GET['q'], array('fragment' => $context->name, 'attributes' => array('class' => array('done'))));
$readable_name = ucwords(str_replace('_', ' ', $context->name));
$description = empty($context->description) ? '' :
"<br/><div class='label bottom'>".check_plain($context->description)."</div>";
$items[] = array(
'data' => "<div class='label top'>" . $readable_name. "</div><div class='links'>{$edit} {$done}</div>" . $description,
'class' => array('context-editable clearfix'),
'id' => "context-editable-trigger-{$context->name}",
);
$form_context = array(
'#tree' => TRUE,
'#type' => module_exists('admin') ? 'admin_panes' : NULL,
'context' => array('#type' => 'value', '#value' => $context),
);
// Edit context reactions.
foreach (array_keys(context_reactions()) as $reaction) {
$plugin = context_get_plugin('reaction', $reaction);
if (method_exists($plugin, 'editor_form') && ($plugin_form = $plugin->editor_form($context))) {
$form_context["reaction-{$reaction}"] = $plugin_form + array('#title' => $plugin->title);
}
}
// Add to main form.
$form['contexts'][$context->name] = $form_context;
}
// Display editable contexts in list.
$form['editables']['#markup'] = theme('item_list', array('items' => $items));
// Buttons.
$form['buttons']['save'] = array(
'#type' => 'submit',
'#value' => t('Save changes'),
'#submit' => array('context_ui_editor_submit'),
);
$form['buttons']['cancel'] = array(
'#type' => 'submit',
'#value' => t('Reset'),
'#submit' => array('context_ui_editor_cancel'),
);
$form['stop'] = array(
'#markup' => l(t('Stop Editing Layout'), 'context-ui/deactivate', array(
'query' => array('destination' => current_path()),
'attributes' => array('class' => array('context_ui_dialog-stop')),
)
),
);
return $form;
}
/**
* Values processor for context_ui_editor_submit().
* Split out for reuse by overriding submit handlers.
*/
function context_ui_editor_process($values) {
$context = $values['context'];
foreach (array_keys(context_conditions()) as $condition) {
if (isset($values['condition'][$condition])) {
$plugin = context_get_plugin('condition', $condition);
if ($plugin && method_exists($plugin, 'editor_form_submit')) {
$context->conditions[$condition]['values'] = $plugin->editor_form_submit($context, $values['condition'][$condition]);
}
}
if (isset($context->conditions[$condition]) && context_empty($context->conditions[$condition]['values'])) {
unset($context->conditions[$condition]);
}
}
foreach (array_keys(context_reactions()) as $reaction) {
if (isset($values["reaction-{$reaction}"])) {
$plugin = context_get_plugin('reaction', $reaction);
if ($plugin && method_exists($plugin, 'editor_form_submit')) {
$context->reactions[$reaction] = $plugin->editor_form_submit($context, $values["reaction-{$reaction}"]);
}
}
if (isset($context->reactions[$reaction]) && context_empty($context->reactions[$reaction])) {
unset($context->reactions[$reaction]);
}
}
return $context;
}
/**
* Save handler for context_block_editor().
*/
function context_ui_editor_submit(&$form, &$form_state) {
foreach ($form_state['values']['contexts'] as $name => $values) {
$original_reactions = var_export($values['context']->reactions, TRUE);
$context = context_ui_editor_process($values);
//compare string values instead of actual objects to avoid problems with aliasing
if (($original_reactions !== var_export($context->reactions, TRUE))) {
if (context_save($context)) {
drupal_set_message(t('Saved %title.', array(
'%title' => (!empty($context->description) ? $context->description : $context->name)
)));
}
else {
drupal_set_message(t('Could not save context %title.', array('%title' => $context->name)), 'error');
}
}
}
return;
}
/**
* Cancel handler for context_block_editor().
*/
function context_ui_editor_cancel(&$form, &$form_state) {
return;
}
/**
* Settings form.
*/
function context_ui_settings($form, &$form_state) {
$form = array();
foreach (context_conditions() as $condition => $info) {
if ($plugin = context_get_plugin('condition', $condition)) {
$settings_form = $plugin->settings_form();
if ($settings_form) {
$form['conditions'][$condition] = $settings_form;
$form['conditions'][$condition]['#tree'] = FALSE;
$form['conditions'][$condition]['#type'] = 'fieldset';
$form['conditions'][$condition]['#title'] = $info['title'];
}
}
}
foreach (context_reactions() as $reaction => $info) {
if ($plugin = context_get_plugin('reaction', $reaction)) {
$settings_form = $plugin->settings_form();
if ($settings_form) {
$form['reactions'][$reaction] = $settings_form;
$form['reactions'][$reaction]['#tree'] = FALSE;
$form['reactions'][$reaction]['#type'] = 'fieldset';
$form['reactions'][$reaction]['#title'] = $info['title'];
}
}
}
$form['context_ui_dialog_enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Use Context Editor Dialog'),
'#default_value' => context_ui_dialog_is_enabled(),
'#description' => t('When enabled all contextual links will have a Edit Layout link that will refresh the page with the context editor in a dialog box.'),
);
$form = system_settings_form($form);
$form['#submit'][] = 'context_ui_settings_submit';
return $form;
}
/**
* Extra submit handler for context_ui_settings.
* Mark the menu cache as needing a rebuild.
*/
function context_ui_settings_submit($form, &$form_state) {
variable_set('menu_rebuild_needed', TRUE);
}
/**
* context_ui_dialog_is_enabled test if the dialog is enabled
*/
function context_ui_dialog_is_enabled() {
return variable_get("context_ui_dialog_enabled", FALSE);
}
/**
* Implementation of hook_page_alter().
*
* If we have the dialog enabled and active build the dialog
* and add to the page
*/
function context_ui_page_alter(&$page) {
$contexts = context_active_contexts();
if (
context_ui_dialog_is_enabled() &&
context_isset('context_ui', 'context_ui_editor_present')
) {
$contexts = context_active_contexts();
$form = drupal_get_form('context_ui_editor', $contexts);
$path = drupal_get_path('module', 'context_ui');
drupal_add_library('system', 'ui.dialog');
drupal_add_js($path . '/context_ui_dialog.js', array('type' => 'file', 'weight' => 50));
drupal_add_css($path . '/context_ui_dialog.css');
//figure out which region to put it in - allow it to be configured for themes using different regions
$placement = variable_get('context_ui_editor_block_region', 'content');
$page[$placement]['context_ui_editor'] = array(
0 => array(
'#type' => 'markup',
'#markup' => '<div style="display:none;" id="context_ui_dialog-context-ui">' . drupal_render($form) . '<!--[if IE 8 ]><div id="context_ui_dialog-shadow"></div><![endif]--></div>',
),
);
}
}
/**
* Implementation of hook_menu_contextual_links_alter().
*
* we we have the dialog enabled lets add a link to all contextual links
* to activate it.
*/
function context_ui_menu_contextual_links_alter(&$links, $router_item, $root_path) {
if(context_ui_dialog_is_enabled() &&
!context_isset('context_ui', 'context_ui_editor_present') && user_access('administer contexts')) {
$links['layout'] = array(
'href' => 'context-ui/activate',
'title' => t('Configure Layout'),
'localized_options' => array(
'query' => array('destination'=> $_GET['q']),
'options' => array('html' => FALSE, 'attributes' => array()),
),
);
}
}
/**
* A page call back to activate the context_ui inline editor dialog.
*/
function context_ui_activate() {
if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) {
$_SESSION['context_ui_active'] = $_GET['destination'];
drupal_goto($_GET['destination']);
}
}
/**
* A page call back to deactivate the context_ui inline editor dialog.
* This is semi unecessary as context editor will auto deactivate upon going to any
* page other than the destination from the start. However, its useful as a place
* to navigate to when deactivating context_ui_editor
*/
function context_ui_deactivate() {
if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) {
$_SESSION['context_ui_active'] = FALSE;
drupal_goto($_GET['destination']);
}
}
/**
* Implemenation of hook_init().
*
* If the session says we should have an active dialog set a context variable to tell everything else
* Ignores ajax requests.
*/
function context_ui_init() {
if (!empty($_SESSION['context_ui_active'])) {
$path = $_SESSION['context_ui_active'];
if( $path == request_path() || $path == drupal_get_path_alias() || $path == drupal_get_normal_path(request_path()) ) {
context_set('context_ui', 'context_ui_editor_present', TRUE);
}
}
// Turn off functionality has been moved to hook_page_build() to prevent non-pages from triggering it
}
/**
* Implementation of hook_page_build().
* Turn off the context_ui functionality if we move to a different page
*/
function context_ui_page_build(&$page) {
if (!context_get('context_ui', 'context_ui_editor_present') && isset($_SESSION['context_ui_active'])) {
$_SESSION['context_ui_active'] = FALSE;
}
}
/**
* Ajax callback to get the list of available blocks
*
*/
function context_ui_get_available_blocks() {
drupal_json_output(array('lols' => 'testing'));
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment