FINAL suepr merge step : added all modules to this super repos

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-19 16:46:59 +02:00
7585 changed files with 1723356 additions and 18 deletions

View File

@@ -0,0 +1,196 @@
<?php
/**
* Base class for a context condition.
*/
class context_condition {
var $plugin;
var $title;
var $description;
var $values = array();
/**
* Clone our references when we're being cloned.
*
* PHP 5.3 performs 'shallow' clones when clone()'ing objects, meaning that
* any objects or arrays referenced by this object will not be copied, the
* cloned object will just reference our objects/arrays instead. By iterating
* over our properties and serializing and unserializing them, we force PHP to
* copy them.
*/
function __clone() {
foreach ($this as $key => $val) {
if (is_object($val) || (is_array($val))) {
$this->{$key} = unserialize(serialize($val));
}
}
}
/**
* Constructor. Do not override.
*/
function __construct($plugin, $info) {
$this->plugin = $plugin;
$this->title = isset($info['title']) ? $info['title'] : $plugin;
$this->description = isset($info['description']) ? $info['description'] : '';
}
/**
* Condition values.
*/
function condition_values() {
return array();
}
/**
* Condition form.
*/
function condition_form($context) {
return array(
'#title' => $this->title,
'#description' => $this->description,
'#options' => $this->condition_values(),
'#type' => 'checkboxes',
'#default_value' => $this->fetch_from_context($context, 'values'),
);
}
/**
* Condition form submit handler.
*/
function condition_form_submit($values) {
ksort($values);
// Editor forms are generally checkboxes -- do some checkbox processing.
return drupal_map_assoc(array_keys(array_filter($values)));
}
/**
* Options form. Provide additional options for your condition.
*/
function options_form($context) {
return array();
}
/**
* Options form submit handler.
*/
function options_form_submit($values) {
return $values;
}
/**
* Settings form. Provide variable settings for your condition.
*/
function settings_form() {
return array();
}
/**
* Context editor form for conditions.
*/
function editor_form($context = NULL) {
$form = array();
if (!empty($this->values)) {
$options = $this->condition_values();
foreach ($this->values as $value => $contexts) {
$label = "{$this->title}: ";
$label .= isset($options[$value]) ? trim($options[$value], ' -') : $value;
$form[$value] = array(
'#type' => 'checkbox',
'#title' => check_plain($label),
'#default_value' => empty($context->name) ? TRUE : in_array($context->name, $contexts, TRUE),
);
}
}
return $form;
}
/**
* Context editor form submit handler.
*/
function editor_form_submit(&$context, $values) {
// Merge existing values in from non-active conditions.
$existing = $this->fetch_from_context($context, 'values');
$values += !empty($existing) ? $existing : array();
ksort($values);
// Editor forms are generally checkboxes -- do some checkbox processing.
return drupal_map_assoc(array_keys(array_filter($values)));
}
/**
* Public method that is called from hooks or other integration points with
* Drupal. Note that it is not implemented in the base class, allowing
* extending classes to change the function signature if necessary.
*
* function execute($value) {
* foreach ($this->get_contexts($value) as $context) {
* $this->condition_met($context, $value);
* }
* }
*/
/**
* Marks a context as having met this particular condition.
*/
function condition_met($context, $value = NULL) {
if (isset($value)) {
$this->values[$value] = isset($this->values[$value]) ? $this->values[$value] : array();
$this->values[$value][] = $context->name;
}
context_condition_met($context, $this->plugin);
}
/**
* Check whether this condition is used by any contexts. Can be used to
* prevent expensive condition checks from being triggered when no contexts
* use this condition.
*/
function condition_used() {
$map = context_condition_map();
return !empty($map[$this->plugin]);
}
/**
* Retrieve all contexts with the condition value provided.
*/
function get_contexts($value = NULL) {
$map = context_condition_map();
$map = isset($map[$this->plugin]) ? $map[$this->plugin] : array();
$contexts = array();
if (isset($value) && (is_string($value) || is_numeric($value))) {
if (isset($map[$value]) && is_array($map[$value])) {
foreach ($map[$value] as $name) {
if (!isset($contexts[$name])) {
$context = context_load($name);
$contexts[$context->name] = $context;
}
}
}
}
else {
foreach ($map as $submap) {
foreach ($submap as $name) {
if (!isset($contexts[$name])) {
$context = context_load($name);
$contexts[$context->name] = $context;
}
}
}
}
return $contexts;
}
/**
* Retrieve options from the context provided.
*/
function fetch_from_context($context, $key = NULL) {
if (isset($key)) {
return isset($context->conditions[$this->plugin][$key]) ? $context->conditions[$this->plugin][$key] : array();
}
return isset($context->conditions[$this->plugin]) ? $context->conditions[$this->plugin] : array();
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* Expose book properties as a context condition.
*/
class context_condition_book extends context_condition {
function condition_values() {
$values = array();
foreach (book_get_books() as $book) {
$values[$book['menu_name']] = check_plain($book['title']);
}
return $values;
}
function execute($node, $op) {
if (isset($node->book, $node->book['menu_name'])) {
foreach ($this->get_contexts($node->book['menu_name']) as $context) {
$this->condition_met($context, $node->book['menu_name']);
}
}
}
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Set the context on the basis of the node type of page's book root.
*/
class context_condition_bookroot extends context_condition_node {
function execute($node, $op) {
if ($this->condition_used() && !empty($node->book['bid'])) {
$type = db_select('node')
->fields('node', array('type'))
->condition('nid', $node->book['nid'])
->execute()
->fetchField();
$book = new stdClass();
$book->type = $type;
parent::execute($book, $op);
}
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Expose active contexts as a context condition.
*/
class context_condition_context extends context_condition_path {
function execute() {
if ($this->condition_used()) {
$active_contexts = array_keys(context_active_contexts());
foreach ($this->get_contexts() as $context) {
if (!in_array($context->name, $active_contexts, TRUE) && $values = $this->fetch_from_context($context, 'values')) {
if ($this->match($active_contexts, $values)) {
$this->condition_met($context);
}
}
}
// If the list of active contexts has changed, we need to recurse.
if ($active_contexts != array_keys(context_active_contexts())) {
$this->execute();
}
}
}
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Expose current language as a context condition.
*/
class context_condition_language extends context_condition {
function condition_values() {
return module_exists('locale') ? locale_language_list() : array();
}
function execute($value) {
foreach ($this->get_contexts($value) as $context) {
$this->condition_met($context, $value);
}
}
}

View File

@@ -0,0 +1,80 @@
<?php
/**
* Expose menu items as a context condition.
*/
class context_condition_menu extends context_condition {
/**
* Override of condition_values().
*/
function condition_values() {
if (module_exists('menu')) {
$menus = menu_parent_options(menu_get_menus(), array('mlid' => 0));
$root_menus = array();
foreach ($menus as $key => $name) {
$id = explode(':', $key);
if ($id[1] == '0') {
$root_menus[$id[0]] = check_plain($name);
}
else {
$link = menu_link_load($id[1]);
$identifier = $link['link_path'];
$root_menu = $root_menus[$id[0]];
while (isset($menus[$root_menu][$identifier])) {
$identifier .= "'";
}
$menus[$root_menu][$identifier] = $name;
}
unset($menus[$key]);
}
array_unshift($menus, "-- " . t('None') . " --");
}
else {
$menus = array();
}
return $menus;
}
/**
* Override of condition_form().
* Use multiselect widget.
*/
function condition_form($context) {
$form = parent::condition_form($context);
$menu_count = count($form['#options'], COUNT_RECURSIVE);
$form['#type'] = 'select';
$form['#multiple'] = TRUE;
$form['#attributes'] = array('size' => $menu_count > 20 ? 20 : $menu_count);
return $form;
}
/**
* Override of condition_form_submit().
* Trim any identifier padding for non-unique path menu items.
*/
function condition_form_submit($values) {
// Trim any identifier padding for non-unique path menu items.
$values = parent::condition_form_submit($values);
$trimmed = array();
foreach ($values as $key => $value) {
$trimmed[trim($key, "'")] = trim($value, "'");
}
return $trimmed;
}
/**
* Override of execute().
*/
function execute() {
if ($this->condition_used()) {
$trail = menu_get_active_trail();
foreach ($trail as $item) {
if (!empty($item['href'])) {
foreach ($this->get_contexts($item['href']) as $context) {
$this->condition_met($context, $item['href']);
}
}
}
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
/**
* Trigger context on node view only.
*/
define('CONTEXT_NODE_VIEW', 0);
/**
* Trigger context on node view and node form.
*/
define('CONTEXT_NODE_FORM', 1);
/**
* Trigger context on node form only.
*/
define('CONTEXT_NODE_FORM_ONLY', 2);
/**
* Expose node views/node forms of specific node types as a context condition.
*/
class context_condition_node extends context_condition {
function condition_values() {
$values = array();
foreach (node_type_get_types() as $type) {
$values[$type->type] = check_plain($type->name);
}
return $values;
}
function options_form($context) {
$defaults = $this->fetch_from_context($context, 'options');
return array(
'node_form' => array(
'#title' => t('Set on node form'),
'#type' => 'select',
'#options' => array(
CONTEXT_NODE_VIEW => t('No'),
CONTEXT_NODE_FORM => t('Yes'),
CONTEXT_NODE_FORM_ONLY => t('Only on node form')
),
'#description' => t('Set this context on node forms'),
'#default_value' => isset($defaults['node_form']) ? $defaults['node_form'] : TRUE,
),
);
}
function execute($node, $op) {
foreach ($this->get_contexts($node->type) as $context) {
// Check the node form option.
$options = $this->fetch_from_context($context, 'options');
if ($op === 'form') {
$options = $this->fetch_from_context($context, 'options');
if (!empty($options['node_form']) && in_array($options['node_form'], array(CONTEXT_NODE_FORM, CONTEXT_NODE_FORM_ONLY))) {
$this->condition_met($context, $node->type);
}
}
elseif (empty($options['node_form']) || $options['node_form'] != CONTEXT_NODE_FORM_ONLY) {
$this->condition_met($context, $node->type);
}
}
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* Expose node taxonomy terms as a context condition.
*/
class context_condition_node_taxonomy extends context_condition_node {
function condition_values() {
$values = array();
if (module_exists('taxonomy')) {
foreach (taxonomy_get_vocabularies() as $vocab) {
if (empty($vocab->tags)) {
foreach (taxonomy_get_tree($vocab->vid) as $term) {
$values[$term->tid] = check_plain($term->name);
}
}
}
}
return $values;
}
function condition_form($context) {
$form = parent::condition_form($context);
$form['#type'] = 'select';
$form['#size'] = 12;
$form['#multiple'] = TRUE;
$vocabularies = taxonomy_get_vocabularies();
$options = array();
foreach ($vocabularies as $vid => $vocabulary) {
$tree = taxonomy_get_tree($vid);
if ($tree && (count($tree) > 0)) {
$options[$vocabulary->name] = array();
foreach ($tree as $term) {
$options[$vocabulary->name][$term->tid] = str_repeat('-', $term->depth) . $term->name;
}
}
}
$form['#options'] = $options;
return $form;
}
function execute($node, $op) {
// build a list of each taxonomy reference field belonging to the bundle for the current node
$fields = field_info_fields();
$instance_fields = field_info_instances('node', $node->type);
$check_fields = array();
foreach ($instance_fields as $key => $field_info) {
if ($fields[$key]['type'] == 'taxonomy_term_reference') {
$check_fields[] = $key;
}
}
if ($this->condition_used() && !empty($check_fields)) {
foreach ($check_fields as $field) {
if ($terms = field_get_items('node', $node, $field)) {
foreach ($terms as $term) {
foreach ($this->get_contexts($term['tid']) as $context) {
// Check the node form option.
if ($op === 'form') {
$options = $this->fetch_from_context($context, 'options');
if (!empty($options['node_form'])) {
$this->condition_met($context, $term['tid']);
}
}
else {
$this->condition_met($context, $term['tid']);
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* Expose paths as a context condition.
*/
class context_condition_path extends context_condition {
/**
* Omit condition values. We will provide a custom input form for our conditions.
*/
function condition_values() {
return array();
}
/**
* Condition form.
*/
function condition_form($context) {
$form = parent::condition_form($context);
unset($form['#options']);
$form['#type'] = 'textarea';
$form['#default_value'] = implode("\n", $this->fetch_from_context($context, 'values'));
return $form;
}
/**
* Condition form submit handler.
*/
function condition_form_submit($values) {
$parsed = array();
$items = explode("\n", $values);
if (!empty($items)) {
foreach ($items as $v) {
$v = trim($v);
if (!empty($v)) {
$parsed[$v] = $v;
}
}
}
return $parsed;
}
/**
* Execute.
*/
function execute() {
if ($this->condition_used()) {
// Include both the path alias and normal path for matching.
$current_path = array(drupal_get_path_alias($_GET['q']));
if ($current_path[0] != $_GET['q']) {
$current_path[] = $_GET['q'];
}
foreach ($this->get_contexts() as $context) {
$paths = $this->fetch_from_context($context, 'values');
if ($this->match($current_path, $paths, TRUE)) {
$this->condition_met($context);
}
}
}
}
/**
* Match the subject against a set of regex patterns.
* Similar to drupal_match_path() but also handles negation through the use
* of the ~ character.
*
* @param mixed $subject
* The subject string or an array of strings to be matched.
* @param array $patterns
* An array of patterns. Any patterns that begin with ~ are considered
* negative or excluded conditions.
* @param boolean $path
* Whether the given subject should be matched as a Drupal path. If TRUE,
* '<front>' will be replaced with the site frontpage when matching against
* $patterns.
*/
protected function match($subject, $patterns, $path = FALSE) {
static $regexps;
$match = FALSE;
$positives = $negatives = 0;
$subject = !is_array($subject) ? array($subject) : $subject;
foreach ($patterns as $pattern) {
if (strpos($pattern, '~') === 0) {
$negate = TRUE;
$negatives++;
}
else {
$negate = FALSE;
$positives++;
}
$pattern = ltrim($pattern, '~');
if (!isset($regexps[$pattern])) {
if ($path) {
$regexps[$pattern] = '/^(' . preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1' . preg_quote(variable_get('site_frontpage', 'node'), '/') . '\2'), preg_quote($pattern, '/')) . ')$/';
}
else {
$regexps[$pattern] = '/^(' . preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/'), array('|', '.*'), preg_quote($pattern, '/')) . ')$/';
}
}
foreach ($subject as $value) {
if (preg_match($regexps[$pattern], $value)) {
if ($negate) {
return FALSE;
}
$match = TRUE;
}
}
}
// If there are **only** negative conditions and we've gotten this far none
// we actually have a match.
if ($positives === 0 && $negatives) {
return TRUE;
}
return $match;
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Simple sitewide context, always present.
*/
class context_condition_sitewide extends context_condition {
function condition_values() {
return array(1 => t('Always active'));
}
function editor_form($context = NULL) {
$form = parent::editor_form($context);
$form[1]['#title'] = t('Always active');
$form['#weight'] = -10;
return $form;
}
function execute($value) {
foreach ($this->get_contexts($value) as $context) {
$this->condition_met($context, $value);
}
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Expose term views/term forms by vocabulary as a context condition.
*/
class context_condition_taxonomy_term extends context_condition {
function condition_values() {
$values = array();
foreach (taxonomy_get_vocabularies() as $vocab) {
$values[$vocab->machine_name] = check_plain($vocab->name);
}
return $values;
}
function options_form($context) {
$defaults = $this->fetch_from_context($context, 'options');
return array(
'term_form' => array(
'#title' => t('Set on term form'),
'#type' => 'select',
'#options' => array(
0 => t('No'),
1 => t('Yes'),
2 => t('Only on term form')
),
'#description' => t('Set this context on term forms'),
'#default_value' => isset($defaults['term_form']) ? $defaults['term_form'] : TRUE,
),
);
}
function execute($term, $op) {
foreach ($this->get_contexts($term->vocabulary_machine_name) as $context) {
// Check the node form option.
$options = $this->fetch_from_context($context, 'options');
if ($op === 'form') {
$options = $this->fetch_from_context($context, 'options');
if (!empty($options['term_form']) && in_array($options['term_form'], array(1, 2))) {
$this->condition_met($context, $term->vocabulary_machine_name);
}
}
elseif (empty($options['term_form']) || $options['term_form'] != 2) {
$this->condition_met($context, $term->vocabulary_machine_name);
}
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
/**
* Expose current user role as a context condition.
*/
class context_condition_user extends context_condition {
function condition_values() {
$values = array();
foreach (user_roles() as $rid => $role_name) {
if ($rid == DRUPAL_ANONYMOUS_RID) {
$values['anonymous user'] = check_plain($role_name);
}
elseif ($rid == DRUPAL_AUTHENTICATED_RID) {
$values['authenticated user'] = check_plain($role_name);
}
else {
$values[$role_name] = check_plain($role_name);
}
}
return $values;
}
function execute($account) {
$roles = $account->roles;
foreach ($roles as $rid => $role) {
foreach ($this->get_contexts($role) as $context) {
$this->condition_met($context, $role);
}
}
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Expose user pages as a context condition.
*/
class context_condition_user_page extends context_condition {
function condition_values() {
$values = array();
$values['view'] = t('User profile');
$values['form'] = t('User account form');
$values['register'] = t('Registration form');
return $values;
}
function options_form($context) {
$defaults = $this->fetch_from_context($context, 'options');
return array(
'mode' => array(
'#title' => t('Active for'),
'#type' => 'select',
'#options' => array(
'all' => t('Any user'),
'current' => t('Only the current user'),
'other' => t('Only other users'),
),
'#default_value' => isset($defaults['mode']) ? $defaults['mode'] : 'all',
),
);
}
function execute($account, $op) {
global $user;
foreach ($this->get_contexts($op) as $context) {
if ($op === 'register') {
$this->condition_met($context);
}
else {
$options = $this->fetch_from_context($context, 'options');
$mode = !empty($options['mode']) ? $options['mode'] : 'all';
switch ($options['mode']) {
case 'current':
if ($account->uid == $user->uid) {
$this->condition_met($context);
}
break;
case 'other':
if ($account->uid != $user->uid) {
$this->condition_met($context);
}
break;
case 'all':
default:
$this->condition_met($context);
break;
}
}
}
}
}

View File

@@ -0,0 +1,48 @@
<?php
class context_condition_views extends context_condition {
/**
* Generate a list of database and module provided views.
*/
function condition_values() {
$enabled_views = array();
$views = views_get_all_views();
ksort($views);
foreach ($views as $view) {
if (!isset($views[$view->name]->disabled) || !$views[$view->name]->disabled) {
$enabled_views[$view->name] = check_plain($view->name);
// Provide more granular options for each page display
$displays = array();
foreach ($view->display as $id => $display) {
if ($display->display_plugin == 'page') {
$displays[$view->name . ":" . $id] = check_plain("-- {$display->display_title}");
}
}
$enabled_views += $displays;
}
}
return $enabled_views;
}
function execute($view) {
switch ($view->display_handler->display->display_plugin) {
case 'page':
case 'calendar':
// Set contexts for this view.
foreach ($this->get_contexts($view->name) as $context) {
$this->condition_met($context, $view->name);
}
// Set any contexts associated with the current display
if (!empty($view->current_display)) {
foreach ($this->get_contexts("{$view->name}:{$view->current_display}") as $context) {
$this->condition_met($context, "{$view->name}:{$view->current_display}");
}
}
break;
}
}
}

View File

@@ -0,0 +1,86 @@
<?php
/**
* Base class for a context reaction.
*/
class context_reaction {
var $plugin;
var $title;
var $description;
/**
* Clone our references when we're being cloned.
*
* PHP 5.3 performs 'shallow' clones when clone()'ing objects, meaning that
* any objects or arrays referenced by this object will not be copied, the
* cloned object will just reference our objects/arrays instead. By iterating
* over our properties and serializing and unserializing them, we force PHP to
* copy them.
*/
function __clone() {
foreach ($this as $key => $val) {
if (is_object($val) || (is_array($val))) {
$this->{$key} = unserialize(serialize($val));
}
}
}
/**
* Constructor. Do not override.
*/
function __construct($plugin, $info) {
$this->plugin = $plugin;
$this->title = isset($info['title']) ? $info['title'] : $plugin;
$this->description = isset($info['description']) ? $info['description'] : '';
}
function options_form($context) {
return array();
}
/**
* Options form submit handler.
*/
function options_form_submit($values) {
return $values;
}
/**
* Settings form. Provide variable settings for your reaction.
*/
function settings_form() {
return array();
}
/**
* Public method that is called from hooks or other integration points with
* Drupal. Note that it is not implemented in the base class, allowing
* extending classes to change the function signature if necessary.
*
* function execute($value) {
* foreach ($this->get_contexts($value) as $context) {
* $this->condition_met($context, $value);
* }
* }
*/
/**
* Retrieve active contexts that have values for this reaction.
*/
function get_contexts() {
$contexts = array();
foreach (context_active_contexts() as $context) {
if ($this->fetch_from_context($context)) {
$contexts[$context->name] = $context;
}
}
return $contexts;
}
/**
* Retrieve options from the context provided.
*/
function fetch_from_context($context) {
return isset($context->reactions[$this->plugin]) ? $context->reactions[$this->plugin] : array();
}
}

View File

@@ -0,0 +1,262 @@
/**
* Script placeholder markup.
*/
.script-placeholder {
padding:100px 0px;
text-align:center;
}
/**
* Browser
*/
.context-block-browser {
width: 600px;
}
.context-block-browser .blocks {
height:98%;
overflow: auto;
float: left;
width: 320px;
}
.context-block-browser .block-browser-sidebar {
float: left;
width: 250px;
padding: 0 0 0 15px;
}
.context-block-item,
.context-block-browser .draggable-placeholder,
#admin-toolbar .context-block-browser .context-block-item {
font-size:11px;
line-height:20px;
height:20px;
color:#333;
padding:3px 3px 3px 3px;
margin:0px 1px 1px 0px;
max-width:300px;
white-space:nowrap;
overflow:hidden;
background:#efefef;
border:1px solid #ddd;
position:relative;
border-radius:5px;
-moz-border-radius:5px;
-moz-user-select:none;
-webkit-user-select:none;
}
.context-block-addable { cursor: pointer; }
.context-block-item span.icon {
background:url(context_reaction_block.png) 0px -80px no-repeat;
display:block;
width:20px;
height:20px;
float:left;
margin-right:5px;
}
.context-block-loading { max-width:none; }
.context-block-loading span.icon {
background-position:-20px -80px;
float:none;
margin:0px auto;
}
.context-block-browser .draggable-placeholder { padding:2px 1px 1px 2px; }
#admin-toolbar.horizontal .context-block-browser .draggable-placeholder,
#admin-toolbar.horizontal .context-block-browser .context-block-item {
width:180px;
margin-right:1px;
padding-right:9px;
float:left;
}
.context-block-added { display:none !important; }
/**
* Inline editing elements ============================================
*/
div.context-block-region {display: none;}
a.context-block { display:none !important; }
body.context-editing div.context-block-region {
-moz-border-radius:5px;
-webkit-border-radius:5px;
background:#666;
color:#fff;
opacity: 0.5;
-moz-opacity: 0.5;
filter:alpha(opacity=50);
display:block;
height:40px;
line-height:24px;
text-align:center;
font-size:18px;
white-space:nowrap;
}
.context-block-region .region-name {
width:100%;
text-align:center;
font-size:18px;
color:#fff;
white-space:nowrap;
display:block;
-moz-user-select:none;
-webkit-user-select:none;
}
body.context-editing .ui-sortable .block { opacity:.25; }
body.context-editing .ui-sortable .draggable {
position:relative;
opacity:1;
}
body.context-editing .draggable-placeholder {
-moz-border-radius:5px;
-webkit-border-radius:5px;
background:#fff;
border:3px dashed #666;
opacity:.2;
}
body.context-editing .draggable:hover a.context-block-remove,
body.context-editing .draggable:hover a.context-block-handle {
background:url(context_reaction_block.png) no-repeat;
cursor:move;
display:block;
width:40px;
height:40px;
position:absolute;
right:35px;
top:-5px;
z-index:100;
}
body.context-editing .draggable:hover a.context-block-remove {
background-position:-40px 0px;
cursor:pointer;
right:-5px;
}
.context-block-hidden { display:none !important; }
.block .context-block-empty-content {
text-align:center;
padding:10px;
opacity:.5;
background:#fff;
color:#666;
}
/**
* Block visibility ===================================================
*/
#context-blockform .context-blockform-selector {
height:20em;
overflow:auto;
}
#context-blockform span.system-blocks { color:#999; }
#context-blockform td.blocks,
#context-blockform td.selector {
border:1px solid #ddd;
padding:10px;
width:50%;
}
#context-blockform td.blocks .label,
#context-blockform td.blocks td,
#context-blockform td.blocks th {
background:#fff;
padding:5px 5px 4px;
border:0px;
border-bottom:1px solid #ddd;
}
#context-blockform td.blocks .label { background:#eee; }
#context-blockform td.blocks .label a { float:right; }
#context-ui-items #context-blockform {
font-size:11px;
line-height:15px;
}
#context-ui-items #context-blockform .form-checkboxes {
height:auto;
overflow:visible;
padding:0px;
margin:0px;
border:0px;
}
#context-ui-items #context-blockform .form-item { padding:0px; }
#context-ui-items #context-blockform label {
background:#eee;
display:block;
padding:5px;
line-height:15px;
}
#context-ui-items #context-blockform label.option {
background:#fff;
display:block;
border:0px;
}
#context-blockform .tabledrag-toggle-weight-wrapper {
margin-bottom:0;
}
a.context-ui-add-link, a:link.context-ui-add-link, a:visited.context-ui-add-link {
display:block;
width:100%;
text-align:center;
font-size:12px;
color:#fff;
cursor: pointer;
line-height:14px;
}
.editing-context-label {
position: fixed;
top:70px;
background:#fff;
color:#222;
padding:10px;
font-weight:bold;
opacity: 0.5;
-moz-opacity: 0.5;
filter:alpha(opacity=50);
border:1px solid #ddd;
border-left:0;
border-radius:0 6px 6px 0;
}
.context-help {
font-size:12px;
font-weight:normal;
}
.context-editor-title {
font-size:24px;
margin:10px 0px;
padding:0;
}

View File

@@ -0,0 +1,673 @@
<?php
/**
* Expose blocks as context reactions.
*/
class context_reaction_block extends context_reaction {
/**
* Options form.
*/
function options_form($context) {
// Rebuild the block info cache if necessary.
$this->get_blocks(NULL, NULL, $this->rebuild_needed());
$this->rebuild_needed(FALSE);
$theme_key = variable_get('theme_default', 'garland');
$weight_delta = $this->max_block_weight();
$form = array(
'#tree' => TRUE,
'#theme' => 'context_block_form',
'max_block_weight' => array(
'#value' => $weight_delta,
'#type' => 'value',
),
'state' => array(
'#type' => 'hidden',
'#attributes' => array('class' => 'context-blockform-state'),
),
);
/**
* Selector.
*/
$modules = module_list();
$form['selector'] = array(
'#type' => 'item',
'#tree' => TRUE,
'#prefix' => '<div class="context-blockform-selector">',
'#suffix' => '</div>',
);
foreach ($this->get_blocks() as $block) {
$group = isset($block->context_group) ? $block->context_group : $block->module;
if (!isset($form['selector'][$group])) {
$form['selector'][$group] = array(
'#type' => 'checkboxes',
'#title' => isset($block->context_group) ? $block->context_group : $modules[$block->module],
'#options' => array(),
);
}
$form['selector'][$group]['#options'][$block->bid] = check_plain($block->info);
}
ksort($form['selector']);
/**
* Regions.
*/
$form['blocks'] = array(
'#tree' => TRUE,
'#theme' => 'context_block_regions_form',
);
foreach (system_region_list($theme_key, REGIONS_VISIBLE) as $region => $label) {
$form['blocks'][$region] = array(
'#type' => 'item',
'#title' => $label,
'#tree' => TRUE,
);
foreach ($this->get_blocks($region, $context) as $block) {
if (!empty($block->context)) {
$form['blocks'][$region][$block->bid] = array(
'#value' => check_plain($block->info),
'#weight' => $block->weight,
'#type' => 'markup',
'#tree' => TRUE,
'weight' => array('#type' => 'weight', '#delta' => $weight_delta, '#default_value' => $block->weight),
);
}
}
}
return $form;
}
/**
* Options form submit handler.
*/
function options_form_submit($values) {
$blocks = array();
$block_info = $this->get_blocks();
// Retrieve blocks from submitted JSON string.
if (!empty($values['state'])) {
$edited = $this->json_decode($values['state']);
}
else {
$edited = array();
}
foreach ($edited as $region => $block_data) {
foreach ($block_data as $position => $data) {
if (isset($block_info[$data->bid])) {
$blocks[$data->bid] = array(
'module' => $block_info[$data->bid]->module,
'delta' => $block_info[$data->bid]->delta,
'region' => $region,
'weight' => $data->weight,
);
}
}
}
return array('blocks' => $blocks);
}
/**
* Context editor form for blocks.
*/
function editor_form($context) {
$form = array();
drupal_add_library('system', 'ui.droppable');
drupal_add_library('system', 'ui.sortable');
drupal_add_js(drupal_get_path('module', 'context_ui') . '/json2.js');
drupal_add_js(drupal_get_path('module', 'context_ui') . '/theme/filter.js');
drupal_add_js(drupal_get_path('module', 'context') . '/plugins/context_reaction_block.js');
drupal_add_css(drupal_get_path('module', 'context') . '/plugins/context_reaction_block.css');
// We might be called multiple times so use a static to ensure this is set just once.
static $once;
if (!isset($once)) {
$settings = array(
'path' => drupal_is_front_page() ? base_path() : url($_GET['q']),
'params' => (object) array_diff_key($_GET, array('q' => '')),
'scriptPlaceholder' => theme('context_block_script_placeholder', array('text' => '')),
);
drupal_add_js(array('contextBlockEditor' => $settings), 'setting');
$once = TRUE;
}
$form['state'] = array(
'#type' => 'hidden',
'#attributes' => array('class' => array('context-block-editor-state')),
);
$form['browser'] = array(
'#markup' => theme('context_block_browser', array(
'blocks' => $this->get_blocks(NULL, NULL, $this->rebuild_needed()),
'context' => $context
)),
);
$this->rebuild_needed(FALSE);
return $form;
}
/**
* Submit handler context editor form.
*/
function editor_form_submit(&$context, $values) {
$edited = !empty($values['state']) ? (array) $this->json_decode($values['state']) : array();
$options = array();
// Take the existing context values and remove blocks that belong affected regions.
$affected_regions = array_keys($edited);
if (!empty($context->reactions['block']['blocks'])) {
$options = $context->reactions['block'];
foreach ($options['blocks'] as $key => $block) {
if (in_array($block['region'], $affected_regions)) {
unset($options['blocks'][$key]);
}
}
}
// Iterate through blocks and add in the ones that belong to the context.
foreach ($edited as $region => $blocks) {
foreach ($blocks as $weight => $block) {
if ($block->context === $context->name) {
$split = explode('-', $block->bid);
$options['blocks'][$block->bid] = array(
'module' => array_shift($split),
'delta' => implode('-', $split),
'region' => $region,
'weight' => $weight,
);
}
}
}
return $options;
}
/**
* Settings form for variables.
*/
function settings_form() {
$form = array();
$form['context_reaction_block_all_regions'] = array(
'#title' => t('Show all regions'),
'#type' => 'checkbox',
'#default_value' => variable_get('context_reaction_block_all_regions', FALSE),
'#description' => t('Show all regions including those that are empty. Enable if you are administering your site using the inline editor.')
);
return $form;
}
/**
* Execute.
*/
function execute(&$page) {
global $theme;
// The theme system might not yet be initialized. We need $theme.
drupal_theme_initialize();
// If the context_block querystring param is set, switch to AJAX rendering.
// Note that we check the output buffer for any content to ensure that we
// are not in the middle of a PHP template render.
if (isset($_GET['context_block']) && !ob_get_contents()) {
return $this->render_ajax($_GET['context_block']);
}
// Populate all block regions
$all_regions = system_region_list($theme);
// Load all region content assigned via blocks.
foreach (array_keys($all_regions) as $region) {
if ($this->is_enabled_region($region)) {
if ($blocks = $this->block_get_blocks_by_region($region)) {
// Are the blocks already sorted.
$blocks_sorted = TRUE;
// If blocks have already been placed in this region (most likely by
// Block module), then merge in blocks from Context.
if (isset($page[$region])) {
$page[$region] = array_merge($page[$region], $blocks);
// Restore the weights that Block module manufactured
// @see _block_get_renderable_array()
foreach ($page[$region] as &$block) {
if (isset($block['#block']->weight)) {
$block['#weight'] = $block['#block']->weight;
$blocks_sorted = FALSE;
}
}
}
else {
$page[$region] = $blocks;
}
$page[$region]['#sorted'] = $blocks_sorted;
}
}
}
}
/**
* Return a list of enabled regions for which blocks should be built.
* Split out into a separate method for easy overrides in extending classes.
*/
protected function is_enabled_region($region) {
global $theme;
$regions = array_keys(system_region_list($theme));
return in_array($region, $regions, TRUE);
}
/**
* Determine whether inline editing requirements are met and that the current
* user may edit.
*/
protected function is_editable_region($region, $reset = FALSE) {
// Check requirements.
// Generally speaking, it does not make sense to allow anonymous users to
// edit a context inline. Though it may be possible to save (and restore)
// an edited context to an anonymous user's cookie or session, it's an
// edge case and probably not something we want to encourage anyway.
static $requirements;
if (!isset($requirements) || $reset) {
global $user;
if ($user->uid && user_access('administer contexts') && variable_get('context_ui_dialog_enabled', FALSE)) {
$requirements = TRUE;
drupal_add_library('system', 'ui.droppable');
drupal_add_library('system', 'ui.sortable');
drupal_add_js(drupal_get_path('module', 'context') . '/plugins/context_reaction_block.js');
drupal_add_css(drupal_get_path('module', 'context') . '/plugins/context_reaction_block.css');
}
else {
$requirements = FALSE;
}
}
// Check that this region is not locked by the theme.
global $theme;
$info = system_get_info('theme', $theme);
if ($info && isset($info['regions_locked']) && in_array($region, $info['regions_locked'])) {
return FALSE;
}
// Check that this region is not hidden
$visible = system_region_list($theme, REGIONS_VISIBLE);
return $requirements && $this->is_enabled_region($region) && isset($visible[$region]);
}
/**
* Add markup for making a block editable.
*/
protected function editable_block($block) {
if (!empty($block->content)) {
$block->content = array(
'content' => $block->content,
'context' => array('#markup' => "<a id='context-block-{$block->module}-{$block->delta}' class='context-block editable edit-{$block->context}'></a>"),
);
//Contextual links are in the wrong spot in the render array once we've nested them
if (isset($block->content['content']['#contextual_links'])) {
$block->content['#contextual_links'] = $block->content['content']['#contextual_links'];
unset($block->content['content']['#contextual_links']);
}
}
else {
// the block alter in context.module should ensure that blocks are never
// empty if the inline editor is present but in the case that they are,
// warn that editing the context is likely to cause this block to be dropped
drupal_set_message(t('The block with delta @delta from module @module is not compatible with the inline editor and will be dropped from the context containing it if you edit contexts here', array('@delta' => $block->delta, '@module' => $block->module)), 'warning');
}
return $block;
}
/**
* Add markup for making a region editable.
*/
protected function editable_region($region, $build) {
if ($this->is_editable_region($region) &&
(!empty($build) ||
variable_get('context_reaction_block_all_regions', FALSE) ||
context_isset('context_ui', 'context_ui_editor_present'))
) {
global $theme;
$regions = system_region_list($theme);
$name = isset($regions[$region]) ? $regions[$region] : $region;
// The negative weight + sorted will push our region marker to the top of the region
$build['context'] = array(
'#prefix' => "<div class='context-block-region' id='context-block-region-{$region}'>",
'#markup' => "<span class='region-name'>{$name}</span>" .
"<a class='context-ui-add-link'>" . t('Add a block here.') . '</a>',
'#suffix' => '</div>',
'#weight' => -100,
);
$build['#sorted'] = FALSE;
}
return $build;
}
/**
* Get a renderable array of a region containing all enabled blocks.
*/
function block_get_blocks_by_region($region) {
module_load_include('module', 'block', 'block');
$build = array();
if ($list = $this->block_list($region)) {
$build = _block_get_renderable_array($list);
}
if ($this->is_editable_region($region)) {
$build = $this->editable_region($region, $build);
}
return $build;
}
/**
* An alternative version of block_list() that provides any context enabled blocks.
*/
function block_list($region) {
module_load_include('module', 'block', 'block');
$context_blocks = &drupal_static('context_reaction_block_list');;
$contexts = context_active_contexts();
if (!isset($context_blocks)) {
$info = $this->get_blocks();
$context_blocks = array();
foreach ($contexts as $context) {
$options = $this->fetch_from_context($context);
if (!empty($options['blocks'])) {
foreach ($options['blocks'] as $context_block) {
$bid = "{$context_block['module']}-{$context_block['delta']}";
if (isset($info[$bid])) {
$block = (object) array_merge((array) $info[$bid], $context_block);
$block->context = $context->name;
$block->title = isset($info[$block->bid]->title) ? $info[$block->bid]->title : NULL;
$block->cache = isset($info[$block->bid]->cache) ? $info[$block->bid]->cache : DRUPAL_NO_CACHE;
$context_blocks[$block->region][$block->bid] = $block;
}
}
}
}
$this->is_editable_check($context_blocks);
foreach ($context_blocks as $r => $blocks) {
$context_blocks[$r] = _block_render_blocks($blocks);
// Make blocks editable if allowed.
if ($this->is_editable_region($r)) {
foreach ($context_blocks[$r] as $key => $block) {
$context_blocks[$r][$key] = $this->editable_block($block);
}
}
// Sort blocks.
uasort($context_blocks[$r], array('context_reaction_block', 'block_sort'));
}
}
return isset($context_blocks[$region]) ? $context_blocks[$region] : array();
}
/**
* Determine if there is an active context editor block, and set a flag. We will set a flag so
* that we can make sure that blocks with empty content have some default content. This is
* needed so the save of the context inline editor does not remove the blocks with no content.
*/
function is_editable_check($context_blocks) {
foreach ($context_blocks as $r => $blocks) {
if (isset($blocks['context_ui-editor'])) {
$block = $blocks['context_ui-editor'];
// see if the editor is actually enabled, lifted from _block_render_blocks
if (!count(module_implements('node_grants')) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
$array = $cache->data;
}
else {
$array = module_invoke($block->module, 'block_view', $block->delta);
drupal_alter(array('block_view', "block_view_{$block->module}_{$block->delta}"), $array, $block);
}
if(!empty($array['content'])) {
context_set('context_ui', 'context_ui_editor_present', TRUE);
}
break;
}
}
}
/**
* Generate the safe weight range for a block being added to a region such that
* there are enough potential unique weights to support all blocks.
*/
protected function max_block_weight() {
$blocks = $this->get_blocks();
$block_count = 0;
foreach ($blocks as $region => $block_list) {
$block_count += count($block_list);
}
// Add 2 to make sure there's space at either end of the block list
return round(($block_count + 2) / 2);
}
/**
* Check or set whether a rebuild of the block info cache is needed.
*/
function rebuild_needed($set = NULL) {
if (isset($set) && $set != variable_get('context_block_rebuild_needed', FALSE)) {
variable_set('context_block_rebuild_needed', $set);
}
return (bool) variable_get('context_block_rebuild_needed', FALSE);
}
/**
* Helper function to generate a list of blocks from a specified region. If provided a context object,
* will generate a full list of blocks for that region distinguishing between system blocks and
* context-provided blocks.
*
* @param $region
* The string identifier for a theme region. e.g. "left"
* @param $context
* A context object.
*
* @return
* A keyed (by "module_delta" convention) array of blocks.
*/
function get_blocks($region = NULL, $context = NULL, $reset = FALSE) {
static $block_info;
$theme_key = variable_get('theme_default', 'garland');
if (!isset($block_info) || $reset) {
$block_info = array();
if (!$reset) {
$block_info = context_cache_get('block_info');
}
if (empty($block_info)) {
if (module_exists('block')) {
$block_blocks = _block_rehash($theme_key);
$block_info = array();
// Change from numeric keys to module-delta.
foreach ($block_blocks as $block) {
$block = (object) $block;
unset($block->theme, $block->status, $block->weight, $block->region, $block->custom, $block->visibility, $block->pages);
$block->bid = "{$block->module}-{$block->delta}";
$block_info[$block->bid] = $block;
}
}
else {
$block_info = array();
foreach (module_implements('block_info') as $module) {
$module_blocks = module_invoke($module, 'block_info');
if (!empty($module_blocks)) {
foreach ($module_blocks as $delta => $block) {
$block = (object) $block;
$block->module = $module;
$block->delta = $delta;
$block->bid = "{$block->module}-{$block->delta}";
$block_info[$block->bid] = $block;
}
}
}
}
context_cache_set('block_info', $block_info);
}
// Allow other modules that may declare blocks dynamically to alter
// this list.
drupal_alter('context_block_info', $block_info);
// Gather only region info from the database.
if (module_exists('block')) {
$result = db_select('block')
->fields('block')
->condition('theme', $theme_key)
->execute();
foreach ($result as $row) {
if (isset($block_info["{$row->module}-{$row->delta}"])) {
$block_info["{$row->module}-{$row->delta}"] = (object) array_merge((array) $row, (array) $block_info["{$row->module}-{$row->delta}"]);
unset($block_info["{$row->module}-{$row->delta}"]->status);
unset($block_info["{$row->module}-{$row->delta}"]->visibility);
}
}
}
}
$blocks = array();
// No region specified, provide all blocks.
if (!isset($region)) {
$blocks = $block_info;
}
// Region specified.
else {
foreach ($block_info as $bid => $block) {
if (isset($block->region) && $block->region == $region) {
$blocks[$bid] = $block;
}
}
}
// Add context blocks if provided.
if (is_object($context) && $options = $this->fetch_from_context($context)) {
if (!empty($options['blocks'])) {
foreach ($options['blocks'] as $block) {
if (
isset($block_info["{$block['module']}-{$block['delta']}"]) && // Block is valid.
(!isset($region) || (!empty($region) && $block['region'] == $region)) // No region specified or regions match.
) {
$context_block = $block_info["{$block['module']}-{$block['delta']}"];
$context_block->weight = $block['weight'];
$context_block->region = $block['region'];
$context_block->context = !empty($context->name) ? $context->name : 'tempname';
$blocks[$context_block->bid] = $context_block;
}
}
}
uasort($blocks, array('context_reaction_block', 'block_sort'));
}
return $blocks;
}
/**
* Sort callback.
*/
static function block_sort($a, $b) {
return ($a->weight - $b->weight);
}
/**
* Compatibility wrapper around json_decode().
*/
protected function json_decode($json, $assoc = FALSE) {
// Requires PHP 5.2.
if (function_exists('json_decode')) {
return json_decode($json, $assoc);
}
return context_reaction_block::_json_decode($json);
}
/**
* From http://www.php.net/manual/en/function.json-decode.php#91216
* with modifications for consistency with output of json_decode().
*
* Original author: walidator.info 2009.
*/
static function _json_decode($json) {
$comment = FALSE;
$out = '$x = ';
for ($i=0; $i < strlen($json); $i++) {
if (!$comment) {
switch ($json[$i]) {
case '{':
$out .= ' (object) array(';
break;
case '}':
$out .= ')';
break;
case '[':
$out .= ' array(';
break;
case ']':
$out .= ')';
break;
case ':';
$out .= '=>';
break;
default:
$out .= $json[$i];
break;
}
}
else {
$out .= $json[$i];
}
if ($json[$i] == '"') {
$comment = !$comment;
}
}
eval($out . ';');
return $x;
}
/**
* Block renderer for AJAX requests. Triggered when $_GET['context_block']
* is set. See ->execute() for how this is called.
*/
function render_ajax($param) {
// Besure the page isn't a 404 or 403.
$headers = drupal_get_http_header();
if (array_key_exists('status', $headers) && ($headers['status'] == "404 Not Found" || $headers['status'] == "403 Forbidden")) {
return;
}
// Set the header right away. This will inform any players in the stack
// that we are in the middle of responding to an AJAX request.
drupal_add_http_header('Content-Type', 'text/javascript; charset=utf-8');
if (strpos($param, ',') !== FALSE) {
list($bid, $context) = explode(',', $param);
list($module, $delta) = explode('-', $bid, 2);
// Check token to make sure user has access to block.
if (empty($_GET['context_token']) || $_GET['context_token'] != drupal_get_token($bid)) {
echo drupal_json_encode(array('status' => 0));
exit;
}
// Ensure $bid is valid.
$info = $this->get_blocks();
if (isset($info[$bid])) {
module_load_include('module', 'block', 'block');
$block = $info[$bid];
$block->title = isset($block->title) ? $block->title : '';
$block->context = $context;
$block->region = '';
$rendered_blocks = _block_render_blocks(array($block)); // For E_STRICT warning
$block = array_shift($rendered_blocks);
if (empty($block->content['#markup'])) {
$block->content['#markup'] = "<div class='context-block-empty'>" . t('This block appears empty when displayed on this page.') . "</div>";
}
$block = $this->editable_block($block);
$renderable_block = _block_get_renderable_array(array($block)); // For E_STRICT warning
echo drupal_json_encode(array(
'status' => 1,
'block' => drupal_render($renderable_block),
));
drupal_exit();
}
}
echo drupal_json_encode(array('status' => 0));
drupal_exit();
}
}

View File

@@ -0,0 +1,501 @@
(function($){
Drupal.behaviors.contextReactionBlock = {attach: function(context) {
$('form.context-editor:not(.context-block-processed)')
.addClass('context-block-processed')
.each(function() {
var id = $(this).attr('id');
Drupal.contextBlockEditor = Drupal.contextBlockEditor || {};
$(this).bind('init.pageEditor', function(event) {
Drupal.contextBlockEditor[id] = new DrupalContextBlockEditor($(this));
});
$(this).bind('start.pageEditor', function(event, context) {
// Fallback to first context if param is empty.
if (!context) {
context = $(this).data('defaultContext');
}
Drupal.contextBlockEditor[id].editStart($(this), context);
});
$(this).bind('end.pageEditor', function(event) {
Drupal.contextBlockEditor[id].editFinish();
});
});
//
// Admin Form =======================================================
//
// ContextBlockForm: Init.
$('#context-blockform:not(.processed)').each(function() {
$(this).addClass('processed');
Drupal.contextBlockForm = new DrupalContextBlockForm($(this));
Drupal.contextBlockForm.setState();
});
// ContextBlockForm: Attach block removal handlers.
// Lives in behaviors as it may be required for attachment to new DOM elements.
$('#context-blockform a.remove:not(.processed)').each(function() {
$(this).addClass('processed');
$(this).click(function() {
$(this).parents('tr').eq(0).remove();
Drupal.contextBlockForm.setState();
return false;
});
});
// Conceal Section title, subtitle and class
$('div.context-block-browser', context).nextAll('.form-item').hide();
}};
/**
* Context block form. Default form for editing context block reactions.
*/
DrupalContextBlockForm = function(blockForm) {
this.state = {};
this.setState = function() {
$('table.context-blockform-region', blockForm).each(function() {
var region = $(this).attr('id').split('context-blockform-region-')[1];
var blocks = [];
$('tr', $(this)).each(function() {
var bid = $(this).attr('id');
var weight = $(this).find('select,input').first().val();
blocks.push({'bid' : bid, 'weight' : weight});
});
Drupal.contextBlockForm.state[region] = blocks;
});
// Serialize here and set form element value.
$('form input.context-blockform-state').val(JSON.stringify(this.state));
// Hide enabled blocks from selector that are used
$('table.context-blockform-region tr').each(function() {
var bid = $(this).attr('id');
$('div.context-blockform-selector input[value='+bid+']').parents('div.form-item').eq(0).hide();
});
// Show blocks in selector that are unused
$('div.context-blockform-selector input').each(function() {
var bid = $(this).val();
if ($('table.context-blockform-region tr#'+bid).size() === 0) {
$(this).parents('div.form-item').eq(0).show();
}
});
};
// make sure we update the state right before submits, this takes care of an
// apparent race condition between saving the state and the weights getting set
// by tabledrag
$('#ctools-export-ui-edit-item-form').submit(function() { Drupal.contextBlockForm.setState(); });
// Tabledrag
// Add additional handlers to update our blocks.
$.each(Drupal.settings.tableDrag, function(base) {
var table = $('#' + base + ':not(.processed)', blockForm);
if (table && table.is('.context-blockform-region')) {
table.addClass('processed');
table.bind('mouseup', function(event) {
Drupal.contextBlockForm.setState();
return;
});
}
});
// Add blocks to a region
$('td.blocks a', blockForm).each(function() {
$(this).click(function() {
var region = $(this).attr('href').split('#')[1];
var base = "context-blockform-region-"+ region;
var selected = $("div.context-blockform-selector input:checked");
if (selected.size() > 0) {
var weight_warn = false;
var min_weight_option = -10;
var max_weight_option = 10;
var max_observed_weight = min_weight_option - 1;
$('table#' + base + ' tr').each(function() {
var weight_input_val = $(this).find('select,input').first().val();
if (+weight_input_val > +max_observed_weight) {
max_observed_weight = weight_input_val;
}
});
selected.each(function() {
// create new block markup
var block = document.createElement('tr');
var text = $(this).parents('div.form-item').eq(0).hide().children('label').text();
var select = '<div class="form-item form-type-select"><select class="tabledrag-hide form-select">';
var i;
weight_warn = true;
var selected_weight = max_weight_option;
if (max_weight_option >= (1 + +max_observed_weight)) {
selected_weight = ++max_observed_weight;
weight_warn = false;
}
for (i = min_weight_option; i <= max_weight_option; ++i) {
select += '<option';
if (i == selected_weight) {
select += ' selected=selected';
}
select += '>' + i + '</option>';
}
select += '</select></div>';
$(block).attr('id', $(this).attr('value')).addClass('draggable');
$(block).html("<td>"+ text + "</td><td>" + select + "</td><td><a href='' class='remove'>X</a></td>");
// add block item to region
//TODO : Fix it so long blocks don't get stuck when added to top regions and dragged towards bottom regions
Drupal.tableDrag[base].makeDraggable(block);
$('table#'+base).append(block);
if ($.cookie('Drupal.tableDrag.showWeight') == 1) {
$('table#'+base).find('.tabledrag-hide').css('display', '');
$('table#'+base).find('.tabledrag-handle').css('display', 'none');
}
else {
$('table#'+base).find('.tabledrag-hide').css('display', 'none');
$('table#'+base).find('.tabledrag-handle').css('display', '');
}
Drupal.attachBehaviors($('table#'+base));
Drupal.contextBlockForm.setState();
$(this).removeAttr('checked');
});
if (weight_warn) {
alert(Drupal.t('Desired block weight exceeds available weight options, please check weights for blocks before saving'));
}
}
return false;
});
});
};
/**
* Context block editor. AHAH editor for live block reaction editing.
*/
DrupalContextBlockEditor = function(editor) {
this.editor = editor;
this.state = {};
this.blocks = {};
this.regions = {};
return this;
};
DrupalContextBlockEditor.prototype = {
initBlocks : function(blocks) {
var self = this;
this.blocks = blocks;
blocks.each(function() {
if($(this).hasClass('context-block-empty')) {
$(this).removeClass('context-block-hidden');
}
$(this).addClass('draggable');
$(this).prepend($('<a class="context-block-handle"></a>'));
$(this).prepend($('<a class="context-block-remove"></a>').click(function() {
$(this).parent ('.block').eq(0).fadeOut('medium', function() {
$(this).remove();
self.updateBlocks();
});
return false;
}));
});
},
initRegions : function(regions) {
this.regions = regions;
var ref = this;
$(regions).not('.context-ui-processed')
.each(function(index, el) {
$('.context-ui-add-link', el).click(function(e){
ref.showBlockBrowser($(this).parent());
}).addClass('context-ui-processed');
});
$('.context-block-browser').hide();
},
showBlockBrowser : function(region) {
var toggled = false;
//figure out the id of the context
var activeId = $('.context-editing', this.editor).attr('id').replace('-trigger', ''),
context = $('#' + activeId)[0];
this.browser = $('.context-block-browser', context).addClass('active');
//add the filter element to the block browser
if (!this.browser.has('input.filter').size()) {
var parent = $('.block-browser-sidebar .filter', this.browser);
var list = $('.blocks', this.browser);
new Drupal.Filter (list, false, '.context-block-addable', parent);
}
//show a dialog for the blocks list
this.browser.show().dialog({
modal : true,
close : function() {
$(this).dialog('destroy');
//reshow all the categories
$('.category', this).show();
$(this).hide().appendTo(context).removeClass('active');
},
height: (.8 * $(window).height()),
minHeight:400,
minWidth:680,
width:680
});
//handle showing / hiding block items when a different category is selected
$('.context-block-browser-categories', this.browser).change(function(e) {
//if no category is selected we want to show all the items
if ($(this).val() == 0) {
$('.category', self.browser).show();
} else {
$('.category', self.browser).hide();
$('.category-' + $(this).val(), self.browser).show();
}
});
//if we already have the function for a different context, rebind it so we don't get dupes
if(this.addToRegion) {
$('.context-block-addable', this.browser).unbind('click.addToRegion')
}
//protected function for adding a clicked block to a region
var self = this;
this.addToRegion = function(e){
var ui = {
'item' : $(this).clone(),
'sender' : $(region)
};
$(this).parents('.context-block-browser.active').dialog('close');
$(region).after(ui.item);
self.addBlock(e, ui, this.editor, activeId.replace('context-editable-', ''));
};
$('.context-block-addable', this.browser).bind('click.addToRegion', this.addToRegion);
},
// Update UI to match the current block states.
updateBlocks : function() {
var browser = $('div.context-block-browser');
// For all enabled blocks, mark corresponding addables as having been added.
$('.block, .admin-block').each(function() {
var bid = $(this).attr('id').split('block-')[1]; // Ugh.
});
// For all hidden addables with no corresponding blocks, mark as addable.
$('.context-block-item', browser).each(function() {
var bid = $(this).attr('id').split('context-block-addable-')[1];
});
// Mark empty regions.
$(this.regions).each(function() {
if ($('.block:has(a.context-block)', this).size() > 0) {
$(this).removeClass('context-block-region-empty');
}
else {
$(this).addClass('context-block-region-empty');
}
});
},
// Live update a region
updateRegion : function(event, ui, region, op) {
switch (op) {
case 'over':
$(region).removeClass('context-block-region-empty');
break;
case 'out':
if (
// jQuery UI 1.8
$('.draggable-placeholder', region).size() === 1 &&
$('.block:has(a.context-block)', region).size() == 0
) {
$(region).addClass('context-block-region-empty');
}
break;
}
},
// Remove script elements while dragging & dropping.
scriptFix : function(event, ui, editor, context) {
if ($('script', ui.item)) {
var placeholder = $(Drupal.settings.contextBlockEditor.scriptPlaceholder);
var label = $('div.handle label', ui.item).text();
placeholder.children('strong').html(label);
$('script', ui.item).parent().empty().append(placeholder);
}
},
// Add a block to a region through an AJAX load of the block contents.
addBlock : function(event, ui, editor, context) {
var self = this;
if (ui.item.is('.context-block-addable')) {
var bid = ui.item.attr('id').split('context-block-addable-')[1];
// Construct query params for our AJAX block request.
var params = Drupal.settings.contextBlockEditor.params;
params.context_block = bid + ',' + context;
if (!Drupal.settings.contextBlockEditor.block_tokens || !Drupal.settings.contextBlockEditor.block_tokens[bid]) {
alert(Drupal.t('An error occurred trying to retrieve block content. Please contact a site administer.'));
return;
}
params.context_token = Drupal.settings.contextBlockEditor.block_tokens[bid];
// Replace item with loading block.
//ui.sender.append(ui.item);
var blockLoading = $('<div class="context-block-item context-block-loading"><span class="icon"></span></div>');
ui.item.addClass('context-block-added');
ui.item.after(blockLoading);
$.getJSON(Drupal.settings.contextBlockEditor.path, params, function(data) {
if (data.status) {
var newBlock = $(data.block);
if ($('script', newBlock)) {
$('script', newBlock).remove();
}
blockLoading.fadeOut(function() {
$(this).replaceWith(newBlock);
self.initBlocks(newBlock);
self.updateBlocks();
Drupal.attachBehaviors(newBlock);
});
}
else {
blockLoading.fadeOut(function() { $(this).remove(); });
}
});
}
else if (ui.item.is(':has(a.context-block)')) {
self.updateBlocks();
}
},
// Update form hidden field with JSON representation of current block visibility states.
setState : function() {
var self = this;
$(this.regions).each(function() {
var region = $('.context-block-region', this).attr('id').split('context-block-region-')[1];
var blocks = [];
$('a.context-block', $(this)).each(function() {
if ($(this).attr('class').indexOf('edit-') != -1) {
var bid = $(this).attr('id').split('context-block-')[1];
var context = $(this).attr('class').split('edit-')[1].split(' ')[0];
context = context ? context : 0;
var block = {'bid': bid, 'context': context};
blocks.push(block);
}
});
self.state[region] = blocks;
});
// Serialize here and set form element value.
$('input.context-block-editor-state', this.editor).val(JSON.stringify(this.state));
},
//Disable text selection.
disableTextSelect : function() {
if ($.browser.safari) {
$('.block:has(a.context-block):not(:has(input,textarea))').css('WebkitUserSelect','none');
}
else if ($.browser.mozilla) {
$('.block:has(a.context-block):not(:has(input,textarea))').css('MozUserSelect','none');
}
else if ($.browser.msie) {
$('.block:has(a.context-block):not(:has(input,textarea))').bind('selectstart.contextBlockEditor', function() { return false; });
}
else {
$(this).bind('mousedown.contextBlockEditor', function() { return false; });
}
},
//Enable text selection.
enableTextSelect : function() {
if ($.browser.safari) {
$('*').css('WebkitUserSelect','');
}
else if ($.browser.mozilla) {
$('*').css('MozUserSelect','');
}
else if ($.browser.msie) {
$('*').unbind('selectstart.contextBlockEditor');
}
else {
$(this).unbind('mousedown.contextBlockEditor');
}
},
// Start editing. Attach handlers, begin draggable/sortables.
editStart : function(editor, context) {
var self = this;
// This is redundant to the start handler found in context_ui.js.
// However it's necessary that we trigger this class addition before
// we call .sortable() as the empty regions need to be visible.
$(document.body).addClass('context-editing');
this.editor.addClass('context-editing');
this.disableTextSelect();
this.initBlocks($('.block:has(a.context-block.edit-'+context+')'));
this.initRegions($('.context-block-region').parent());
this.updateBlocks();
$('a.context_ui_dialog-stop').hide();
$('.editing-context-label').remove();
var label = $('#context-editable-trigger-'+context+' .label').text();
label = Drupal.t('Now Editing: ') + label;
editor.parent().parent()
.prepend('<div class="editing-context-label">'+ label + '</div>');
// First pass, enable sortables on all regions.
$(this.regions).each(function() {
var region = $(this);
var params = {
revert: true,
dropOnEmpty: true,
placeholder: 'draggable-placeholder',
forcePlaceholderSize: true,
items: '> .block:has(a.context-block.editable)',
handle: 'a.context-block-handle',
start: function(event, ui) { self.scriptFix(event, ui, editor, context); },
stop: function(event, ui) { self.addBlock(event, ui, editor, context); },
receive: function(event, ui) { self.addBlock(event, ui, editor, context); },
over: function(event, ui) { self.updateRegion(event, ui, region, 'over'); },
out: function(event, ui) { self.updateRegion(event, ui, region, 'out'); },
cursorAt: {left: 300, top: 0}
};
region.sortable(params);
});
// Second pass, hook up all regions via connectWith to each other.
$(this.regions).each(function() {
$(this).sortable('option', 'connectWith', ['.ui-sortable']);
});
// Terrible, terrible workaround for parentoffset issue in Safari.
// The proper fix for this issue has been committed to jQuery UI, but was
// not included in the 1.6 release. Therefore, we do a browser agent hack
// to ensure that Safari users are covered by the offset fix found here:
// http://dev.jqueryui.com/changeset/2073.
if ($.ui.version === '1.6' && $.browser.safari) {
$.browser.mozilla = true;
}
},
// Finish editing. Remove handlers.
editFinish : function() {
this.editor.removeClass('context-editing');
this.enableTextSelect();
$('.editing-context-label').remove();
// Remove UI elements.
$(this.blocks).each(function() {
$('a.context-block-handle, a.context-block-remove', this).remove();
if($(this).hasClass('context-block-empty')) {
$(this).addClass('context-block-hidden');
}
$(this).removeClass('draggable');
});
$('a.context_ui_dialog-stop').show();
this.regions.sortable('destroy');
this.setState();
// Unhack the user agent.
if ($.ui.version === '1.6' && $.browser.safari) {
$.browser.mozilla = false;
}
}
}; //End of DrupalContextBlockEditor prototype
})(jQuery);

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,256 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="80"
height="120"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.46"
version="1.0"
sodipodi:docname="context_reaction_block.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/devseed/kitrium/profiles/openatrium/modules/contrib/context/plugins/context_reaction_block.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient3186">
<stop
style="stop-color:#000000;stop-opacity:0.1254902"
offset="0"
id="stop3188" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop3190" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3191">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3193" />
<stop
style="stop-color:#c0c0c0;stop-opacity:1"
offset="1"
id="stop3195" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3191"
id="linearGradient3197"
x1="10"
y1="10"
x2="10"
y2="30"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3191"
id="linearGradient3199"
gradientUnits="userSpaceOnUse"
x1="10"
y1="10"
x2="10"
y2="30" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3191"
id="linearGradient3176"
gradientUnits="userSpaceOnUse"
x1="18"
y1="81"
x2="18"
y2="99" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3186"
id="linearGradient3192"
x1="2"
y1="92.5"
x2="10"
y2="92.5"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3191"
id="linearGradient3255"
gradientUnits="userSpaceOnUse"
x1="18"
y1="81"
x2="18"
y2="99" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3191"
id="linearGradient3260"
gradientUnits="userSpaceOnUse"
x1="18"
y1="81"
x2="18"
y2="99" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3191"
id="linearGradient3265"
gradientUnits="userSpaceOnUse"
x1="18"
y1="81"
x2="18"
y2="99" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3191"
id="linearGradient3276"
gradientUnits="userSpaceOnUse"
x1="18"
y1="81"
x2="18"
y2="99" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3191"
id="linearGradient3284"
gradientUnits="userSpaceOnUse"
x1="18"
y1="81"
x2="18"
y2="99" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="31.144684"
inkscape:cy="24.681366"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false">
<inkscape:grid
type="xygrid"
id="grid2383"
visible="true"
enabled="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:nodetypes="ccccsccccccccccssccsccc"
id="path3287"
d="M 30,84.5 C 27.8265,84.5 25.87799,85.506572 24.59375,87.0625 L 24.59375,87.09375 L 26,88.5 C 26.912944,87.291403 28.369734,86.5 30,86.5 C 32.044638,86.5 33.787894,87.740652 34.5625,89.5 L 31.5,89.5 L 35.5,93.5 L 39.5,89.5 L 39,89.5 L 36.6875,89.5 C 35.825628,86.615704 33.164199,84.5 30,84.5 z M 24.5,89.5 L 20.5,93.5 L 23.3125,93.5 C 24.174372,96.384296 26.835801,98.5 30,98.5 C 32.1735,98.5 34.12201,97.493428 35.40625,95.9375 C 35.411546,95.931083 35.400976,95.912686 35.40625,95.90625 L 34,94.5 C 33.087056,95.708597 31.630266,96.5 30,96.5 C 27.955362,96.5 26.212106,95.259348 25.4375,93.5 L 28.5,93.5 L 24.5,89.5 z"
style="opacity:1;fill:#000000;fill-opacity:0.50196078000000000;fill-rule:nonzero;stroke:none;stroke-width:1.25000000000000000;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;color:#000000" />
<rect
style="opacity:1;fill:#404040;fill-opacity:0.75294118;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2385"
width="80"
height="40"
x="0"
y="0"
rx="10"
ry="10" />
<path
id="path3183"
d="M 20,12.5 L 17,15.5 L 19,15.5 L 19,20.5 L 14,20.5 L 14,18.5 L 11,21.5 L 14,24.5 L 14,22.5 L 19,22.5 L 19,27.5 L 17,27.5 L 20,30.5 L 23,27.5 L 21,27.5 L 21,22.5 L 26,22.5 L 26,24.5 L 29,21.5 L 26,18.5 L 26,20.5 L 21,20.5 L 21,15.5 L 23,15.5 L 20,12.5 z"
style="opacity:1;fill:#000000;fill-opacity:0.50196078;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
style="opacity:1;fill:url(#linearGradient3199);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 20,11 L 17,14 L 19,14 L 19,19 L 14,19 L 14,17 L 11,20 L 14,23 L 14,21 L 19,21 L 19,26 L 17,26 L 20,29 L 23,26 L 21,26 L 21,21 L 26,21 L 26,23 L 29,20 L 26,17 L 26,19 L 21,19 L 21,14 L 23,14 L 20,11 z"
id="path3161" />
<path
id="path3185"
d="M 55.5,15.21875 C 55.372191,15.21875 55.254184,15.245816 55.15625,15.34375 L 53.84375,16.65625 C 53.647881,16.852119 53.647881,17.147881 53.84375,17.34375 L 58,21.5 L 53.84375,25.65625 C 53.647883,25.852118 53.647881,26.147881 53.84375,26.34375 L 55.15625,27.65625 C 55.352118,27.852119 55.647881,27.852119 55.84375,27.65625 L 60,23.5 L 64.15625,27.65625 C 64.352119,27.852119 64.64788,27.852119 64.84375,27.65625 L 66.15625,26.34375 C 66.352119,26.147881 66.352117,25.852118 66.15625,25.65625 L 62,21.5 L 66.15625,17.34375 C 66.352119,17.147882 66.352119,16.852119 66.15625,16.65625 L 64.84375,15.34375 C 64.64788,15.147881 64.352119,15.147881 64.15625,15.34375 L 60,19.5 L 55.84375,15.34375 C 55.745816,15.245816 55.627809,15.21875 55.5,15.21875 z"
style="opacity:1;fill:#000000;fill-opacity:0.50196078;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
style="opacity:1;fill:url(#linearGradient3197);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 55.5,13.71875 C 55.372191,13.71875 55.254184,13.745816 55.15625,13.84375 L 53.84375,15.15625 C 53.647881,15.352119 53.647881,15.647881 53.84375,15.84375 L 58,20 L 53.84375,24.15625 C 53.647883,24.352118 53.647881,24.647881 53.84375,24.84375 L 55.15625,26.15625 C 55.352118,26.352119 55.647881,26.352119 55.84375,26.15625 L 60,22 L 64.15625,26.15625 C 64.352119,26.352119 64.64788,26.352119 64.84375,26.15625 L 66.15625,24.84375 C 66.352119,24.647881 66.352117,24.352118 66.15625,24.15625 L 62,20 L 66.15625,15.84375 C 66.352119,15.647882 66.352119,15.352119 66.15625,15.15625 L 64.84375,13.84375 C 64.64788,13.647881 64.352119,13.647881 64.15625,13.84375 L 60,18 L 55.84375,13.84375 C 55.745816,13.745816 55.627809,13.71875 55.5,13.71875 z"
id="rect3173" />
<rect
style="opacity:1;fill:#404040;fill-opacity:0.50196078;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3179"
width="1"
height="30"
x="40"
y="5"
ry="0.5"
rx="0.5" />
<rect
y="40"
x="0"
height="40"
width="80"
id="rect2391"
style="opacity:1;fill:#404040;fill-opacity:0.75294118;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<g
id="g3215">
<rect
style="opacity:1;fill:#000000;fill-opacity:0.50196078000000000;fill-rule:nonzero;stroke:none;stroke-width:1.25000000000000000;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;color:#000000"
id="rect3200"
width="14"
height="14"
x="3"
y="84.5"
rx="2"
ry="2" />
<path
style="fill:url(#linearGradient3176);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:0;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 5,83 L 15,83 C 16.108,83 17,83.892 17,85 L 17,95 C 17,96.108 16.108,97 15,97 L 5,97 C 3.892,97 3,96.108 3,95 L 3,85 C 3,83.892 3.892,83 5,83 z"
id="rect3198" />
<rect
ry="0.5"
rx="0.5"
y="87"
x="5"
height="8"
width="10"
id="rect3206"
style="opacity:1;fill:#000000;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:1.25000000000000000;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
id="rect3208"
d="M 5.5 87 C 5.223 87 5 87.223 5 87.5 L 5 94 L 6 88 L 14 88 L 15 94 L 15 87.5 C 15 87.223 14.777 87 14.5 87 L 5.5 87 z "
style="opacity:1;fill:#000000;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:1.25;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<path
style="opacity:1;fill:url(#linearGradient3284);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000000000000000;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;color:#000000"
d="M 30,83 C 27.8265,83 25.87799,84.006572 24.59375,85.5625 L 24.59375,85.59375 L 26,87 C 26.912944,85.791403 28.369734,85 30,85 C 32.044638,85 33.787894,86.240652 34.5625,88 L 31.5,88 L 35.5,92 L 39.5,88 L 39,88 L 36.6875,88 C 35.825628,85.115704 33.164199,83 30,83 z M 24.5,88 L 20.5,92 L 23.3125,92 C 24.174372,94.884296 26.835801,97 30,97 C 32.1735,97 34.12201,95.993428 35.40625,94.4375 C 35.411546,94.431083 35.400976,94.412686 35.40625,94.40625 L 34,93 C 33.087056,94.208597 31.630266,95 30,95 C 27.955362,95 26.212106,93.759348 25.4375,92 L 28.5,92 L 24.5,88 z"
id="path3231"
sodipodi:nodetypes="ccccsccccccccccssccsccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,39 @@
<?php
/**
* Set the breadcrumb using a context reaction.
*/
class context_reaction_breadcrumb extends context_reaction_menu {
/**
* Override of execute().
*/
function execute(&$vars = NULL) {
if ($active_paths = $this->get_active_paths()) {
$breadcrumb = array(l(t('Home'), '<front>', array('purl' => array('disabled' => TRUE))));
foreach ($active_paths as $path) {
$result = db_select('menu_links')
->fields('menu_links', array('p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8'))
->condition('hidden', 0)
->condition('link_path', $path)
->execute();
while ($parents = $result->fetchAssoc()) {
$set = FALSE;
foreach (array_filter($parents) as $plid) {
$parent = menu_link_load($plid);
if ($parent && $parent['access'] && empty($parent['hidden']) && !empty($parent['title'])) {
$set = TRUE;
$breadcrumb[] = l($parent['title'], $parent['href']);
}
}
// Only set the breadcrumb if one or more links were added to the
// trail. If not, continue iterating through possible menu links.
if ($set) {
drupal_set_breadcrumb($breadcrumb);
break;
}
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
class context_reaction_css_injector extends context_reaction {
function options_form($context) {
$list = array();
foreach (_css_injector_load_rule() as $css_rule) {
$list[$css_rule['crid']] = $css_rule['title'];
}
ksort($list);
return array(
'#title' => $this->title,
'#description' => $this->description,
'#options' => $list,
'#type' => 'checkboxes',
'#default_value' => $this->fetch_from_context($context),
);
}
function execute() {
$contexts = $this->get_contexts();
foreach ($contexts as $context) {
if (!empty($context->reactions[$this->plugin])) {
foreach ($context->reactions[$this->plugin] as $crid => $enabled) {
if ($enabled && $css_rule = _css_injector_load_rule($crid)) {
drupal_add_css(_css_injector_rule_uri($crid), 'module', $css_rule['media'], $css_rule['preprocess']);
}
}
}
}
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* Output context debug information.
*/
class context_reaction_debug extends context_reaction {
function options_form($context) {
return array('debug' => array('#type' => 'value', '#value' => TRUE));
}
function options_form_submit($values) {
return array('debug' => 1);
}
/**
* Output a list of active contexts.
*/
function execute() {
$contexts = context_active_contexts();
foreach ($contexts as $context) {
if (!empty($context->reactions['debug'])) {
if (user_access('administer site configuration') && module_exists('context_ui')) {
$name = l($context->name, "admin/structure/context/list/{$context->name}", array('query' => array('destination' => $_GET['q'])));
}
else {
$name = check_plain($context->name);
}
drupal_set_message(t("Active context: !name", array('!name' => $name)));
}
}
}
}

View File

@@ -0,0 +1,142 @@
<?php
/**
* Expose menu items as context reactions.
*/
class context_reaction_menu extends context_reaction {
/**
* Provide a form element that allow the admin to chose a menu item.
*/
function options_form($context) {
if (module_exists('menu')) {
$menus = menu_parent_options(menu_get_menus(), array('mlid' => 0));
$root_menus = array();
foreach ($menus as $key => $name) {
$id = explode(':', $key);
if ($id[1] == '0') {
$root_menus[$id[0]] = check_plain($name);
}
else {
$link = menu_link_load($id[1]);
$identifier = $link['link_path'];
$root_menu = $root_menus[$id[0]];
while (isset($menus[$root_menu][$identifier])) {
$identifier .= "'";
}
$menus[$root_menu][$identifier] = $name;
}
unset($menus[$key]);
}
array_unshift($menus, "-- " . t('None') . " --");
}
else {
$menus = array();
}
return array(
'#title' => $this->title,
'#description' => $this->description,
'#options' => $menus,
'#type' => 'select',
'#default_value' => $this->fetch_from_context($context),
);
}
/**
* Override of options_form_submit().
* Trim any identifier padding for non-unique path menu items.
*/
function options_form_submit($values) {
return trim($values, "'");
}
/**
* If primary + secondary links are pointed at the same menu, provide
* contextual trailing by default.
*/
function execute(&$vars = NULL) {
if (variable_get('menu_main_links_source', 'main-menu') == variable_get('menu_secondary_links_source', 'user-menu')) {
$vars['main_menu'] = theme_get_setting('toggle_main_menu') ? $this->menu_navigation_links(variable_get('menu_main_links_source', 'main-menu')) : $vars['main_menu'];
$vars['secondary_menu'] = theme_get_setting('toggle_secondary_menu') ? $this->menu_navigation_links(variable_get('menu_secondary_links_source', 'secondary-links'), 1) : $vars['secondary_menu'];
}
$vars['main_menu'] = $this->menu_set_active($vars['main_menu']);
$vars['secondary_menu'] = $this->menu_set_active($vars['secondary_menu']);
}
function get_active_paths() {
$active_paths = array();
foreach ($this->get_contexts() as $context) {
if (isset($context->reactions[$this->plugin])) {
$active_paths[] = $context->reactions[$this->plugin];
}
}
return $active_paths;
}
/**
* Iterates through a provided links array for use with theme_links()
* (e.g. from menu_primary_links()) and provides an active class for
* any items that have a path that matches an active context.
*
* @param $links
* An array of links.
* @param $reset
* A boolean flag for resetting the static cache.
*
* @return
* A modified links array.
*/
function menu_set_active($links = array(), $reset = FALSE) {
$new_links = array();
if (!empty($links)) {
$active_paths = $this->get_active_paths();
// Iterate through the provided links and build a new set of links
// that includes active classes
foreach ($links as $key => $link) {
if (!empty($link['href']) && in_array($link['href'], $active_paths)) {
$link['attributes']['class'][] = 'active';
if (strpos(' active', $key) === FALSE) {
$new_links[$key . ' active'] = $link;
}
}
else {
$new_links[$key] = $link;
}
}
}
return $new_links;
}
/**
* Wrapper around menu_navigation_links() that gives themers the option of
* building navigation links based on an active context trail.
*/
function menu_navigation_links($menu_name, $level = 0) {
// Retrieve original path so we can repair it after our hack.
$original_path = $_GET['q'];
$original_menu_trail = drupal_static('menu_set_active_trail');
// Retrieve the first active menu path found.
if ($active_paths = $this->get_active_paths()) {
$path = current($active_paths);
if (menu_get_item($path)) {
menu_set_active_item($path);
}
}
// Build the links requested
if (module_exists('i18n_menu')) {
$links = i18n_menu_navigation_links($menu_name, $level);
} else {
$links = menu_navigation_links($menu_name, $level);
}
// Repair and get out
menu_set_active_item($original_path);
$repair_menu_trail = &drupal_static('menu_set_active_trail');
$repair_menu_trail = $original_menu_trail;
return $links;
}
}

View File

@@ -0,0 +1,46 @@
<?php
class context_reaction_region extends context_reaction {
function editor_form($context) {
}
function options_form($context) {
$values = $this->fetch_from_context($context);
$form = array();
foreach (list_themes() as $theme) {
if ($theme->status) {
$regions = system_region_list($theme->name);
$default = isset($values[$theme->name]) ? $values[$theme->name]['disable'] : array();
$form[$theme->name] = array(
'#type' => 'fieldset',
'#title' => "Disable Regions in {$theme->name} Theme",
'#collapsible' => TRUE,
'#collapsed' => !array_reduce($default, create_function('$a, $b', 'return $a || $b;')),
);
$form[$theme->name]['disable'] = array(
'#type' => 'checkboxes',
'#title' => t("Disable the following"),
'#options' => $regions,
'#default_value' => $default,
);
}
}
return $form;
}
function execute(&$page) {
global $theme;
foreach ($this->get_contexts() as $k => $v) {
if (isset($v->reactions[$this->plugin][$theme])) {
$regions = $v->reactions[$this->plugin][$theme]['disable'];
foreach ($regions as $region => $disable) {
if ($disable && isset($page[$region])) {
unset($page[$region]);
}
}
}
}
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* Expose themes as context reactions.
*/
class context_reaction_theme extends context_reaction {
/**
* Editor form.
*/
function editor_form($context) {
$form = $this->options_form($context);
// Hide descriptions which take up too much space.
unset($form['title']['#description']);
unset($form['subtitle']['#description']);
unset($form['class']['#description']);
return $form;
}
/**
* Submit handler for editor form.
*/
function editor_form_submit($context, $values) {
return $values;
}
/**
* Allow admins to provide a section title, section subtitle and section class.
*/
function options_form($context) {
$values = $this->fetch_from_context($context);
$form = array(
'#tree' => TRUE,
'#title' => t('Theme variables'),
'title' => array(
'#title' => t('Section title'),
'#description' => t('Provides this text as a <strong>$section_title</strong> variable for display in page.tpl.php when this context is active.'),
'#type' => 'textfield',
'#maxlength' => 255,
'#default_value' => isset($values['title']) ? $values['title'] : '',
),
'subtitle' => array(
'#title' => t('Section subtitle'),
'#description' => t('Provides this text as a <strong>$section_subtitle</strong> variable for display in page.tpl.php when this context is active.'),
'#type' => 'textfield',
'#maxlength' => 255,
'#default_value' => isset($values['subtitle']) ? $values['subtitle'] : '',
),
);
return $form;
}
/**
* Set 'section_title', and 'section_subtitle' if not set
*/
function execute(&$vars) {
$classes = array();
foreach ($this->get_contexts() as $k => $v) {
if (!empty($v->reactions[$this->plugin]['title']) && !isset($vars['section_title'])) {
$vars['section_title'] = check_plain(t($v->reactions[$this->plugin]['title']));
}
if (!empty($v->reactions[$this->plugin]['subtitle']) && !isset($vars['section_subtitle'])) {
$vars['section_subtitle'] = check_plain(t($v->reactions[$this->plugin]['subtitle']));
}
}
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Expose themes as context reactions.
*/
class context_reaction_theme_html extends context_reaction_theme {
/**
* Allow admins to provide additional body classes.
*/
function options_form($context) {
$values = $this->fetch_from_context($context);
$form = array(
'class' => array(
'#title' => t('Section class'),
'#description' => t('Provides this text as an additional body class (in <strong>$classes</strong> in html.tpl.php) when this section is active.'),
'#type' => 'textfield',
'#maxlength' => 64,
'#default_value' => isset($values['class']) ? $values['class'] : '',
),
);
return $form;
}
/**
* Set additional classes onto the 'body_classes'.
*/
function execute(&$vars) {
$classes = array();
foreach ($this->get_contexts() as $k => $v) {
if (!empty($v->reactions[$this->plugin]['class'])) {
$vars['classes_array'][] = $v->reactions[$this->plugin]['class'];
}
}
}
}