diff --git a/context_ui/context_ui.css b/context_ui/context_ui.css index 4c2231e..7ff7d0c 100644 --- a/context_ui/context_ui.css +++ b/context_ui/context_ui.css @@ -1,8 +1,17 @@ /** * Editor ============================================================= */ -div.context-editor div.label { float:left; } +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; } @@ -89,7 +98,7 @@ table.context-admin input.form-text { width:90%; } .context-plugins { position:relative; margin:0px 0px 10px; - } +} .context-plugins .context-plugin-info { padding:10px 10px 9px; diff --git a/context_ui/context_ui.module b/context_ui/context_ui.module index adf927b..ddc4881 100644 --- a/context_ui/context_ui.module +++ b/context_ui/context_ui.module @@ -53,7 +53,7 @@ function context_ui_block_info() { function context_ui_block_view($delta = '') { switch ($delta) { case 'editor': - if (user_access('administer site configuration') && strpos($_GET['q'], 'admin/structure/context') === FALSE && $contexts = context_active_contexts()) { + 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), @@ -72,6 +72,18 @@ function context_ui_block_view($delta = '') { } /** + * 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.' + ); + return $permissions; +} + +/** * Implementation of hook_menu(). */ function context_ui_menu() { @@ -79,12 +91,24 @@ function context_ui_menu() { $items['admin/structure/context/settings'] = array( 'title' => 'Settings', 'access callback' => 'user_access', - 'access arguments' => array('administer site configuration'), + '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; } @@ -113,15 +137,35 @@ function context_ui_editor($form, &$form_state, $contexts) { 'buttons' => array('#tree' => FALSE), ); + $form['title'] = array( + '#prefix' => '

', + '#markup' => t('Select the Context/Layer to Edit'), + '#suffix' => '

', + '#weight' => -2, + ); + + //add some help text to the top of the form + $form['help'] = array ( + '#prefix' => '

', + '#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' => '

', + '#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) ? '' : + "
".check_plain($context->description)."
"; $items[] = array( - 'data' => "
" . (empty($context->description) ? $context->name : check_plain($context->description)) ."
", + 'data' => "
" . $readable_name. "
" . $description, 'class' => array('context-editable clearfix'), 'id' => "context-editable-trigger-{$context->name}", ); @@ -131,18 +175,6 @@ function context_ui_editor($form, &$form_state, $contexts) { 'context' => array('#type' => 'value', '#value' => $context), ); - // Edit context conditions. - foreach (array_keys(context_conditions()) as $condition) { - $plugin = context_get_plugin('condition', $condition); - if (method_exists($plugin, 'editor_form') && ($plugin_form = $plugin->editor_form($context))) { - $form_context['condition'][$condition] = $plugin_form; - } - } - if (count(element_children($form_context['condition']))) { - $form_context['condition']['#title'] = t('Conditions'); - $form_context['condition']['#description'] = t('This context is active when any of the selected conditions are true.'); - } - // Edit context reactions. foreach (array_keys(context_reactions()) as $reaction) { $plugin = context_get_plugin('reaction', $reaction); @@ -166,9 +198,18 @@ function context_ui_editor($form, &$form_state, $contexts) { ); $form['buttons']['cancel'] = array( '#type' => 'submit', - '#value' => t('Cancel'), + '#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' => request_path()), + 'attributes' => array('class' => array('context_ui_dialog-stop')), + ) + ), + ); + return $form; } @@ -208,10 +249,10 @@ function context_ui_editor_process($values) { */ function context_ui_editor_submit(&$form, &$form_state) { foreach ($form_state['values']['contexts'] as $name => $values) { - $original_conditions = $values['context']->conditions; - $original_reactions = $values['context']->reactions; + $original_reactions = var_export($values['context']->reactions, TRUE); $context = context_ui_editor_process($values); - if (($original_conditions !== $context->conditions) || ($original_reactions !== $context->reactions)) { + //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) @@ -259,6 +300,12 @@ function context_ui_settings($form, &$form_state) { } } } + $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; @@ -271,3 +318,105 @@ function context_ui_settings($form, &$form_state) { 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' => '', + ), + ); + } +} + +/** + * 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')) { + $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() { + $_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() { + $_SESSION['context_ui_active'] = FALSE; + drupal_goto($_GET['destination']); +} + +/** + * Implemenation of hook_init(). + * + * if the session say we should have an active dialog set a context variable to tell everything else + */ +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); + return; + } + } +} + +/** + * Ajax callback to get the list of available blocks + * + */ +function context_ui_get_available_blocks() { + drupal_json_output(array('lols' => 'testing')); +} \ No newline at end of file diff --git a/context_ui/context_ui_dialog.css b/context_ui/context_ui_dialog.css new file mode 100644 index 0000000..e226782 --- /dev/null +++ b/context_ui/context_ui_dialog.css @@ -0,0 +1,93 @@ + +#context_ui_dialog-context-ui a, #context_ui_dialog-context-ui li a.active { + color: #222; +} +#context_ui_dialog-context-ui ul { + margin: 0; +} +#context_ui_dialog-context-ui ul li { + padding: 4px 0; + list-style: none; +} + +#context_ui_dialog-context-ui .buttons { + padding-top:15px; +} + +#context_ui_dialog-context-ui div.admin-pane-condition, +#context_ui_dialog-context-ui div.admin-pane-reaction-theme, +#context_ui_dialog-context-ui div.admin-pane-reaction-theme_html { + display: none; +} + +.boxes-box-editing { + background: none repeat scroll 0 0 #EEEEDD; + display: inline-block; + padding: 3px; +} + +body.context-editing div.contextual-links-wrapper { + right: 0; + top: 40px; +} + +#context_ui_dialog-context-ui a.context_ui_dialog-stop, +#context_ui_dialog-context-ui a:link.context_ui_dialog-stop, +#context_ui_dialog-context-ui a:visited.context_ui_dialog-stop { + float:right; + padding-top:18px; + color: #ad3f00; +} + +form.context-editing li.context-editable { + opacity: .2; +} +form.context-editing li.context-editing { + visibility : visible; + display : list-item; + opacity: 1; +} +#context_ui_dialog-context-ui { + width: 550px; + position:fixed; + background:#fff; + color:#222; + top:140px; + display:none; + z-index:400; + padding:10px; + font-weight:bold; + border:1px solid #ddd; + border-left:0; + border-radius:0 6px 6px 0; + /* Shadow */ + -moz-box-shadow: 3px 3px 4px #555; + -webkit-box-shadow: 3px 3px 4px #555; + box-shadow: 3px 3px 4px #555; + /* For IE 8 */ + -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#555555')"; + /* For IE 5.5 - 7 */ + filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#555555'); +} + +.context-ui-dialog-open { + border-radius:0 6px 6px 0; + position: absolute; + background:#fff; + color:#222; + top: 50px; + padding: 10px; + width: 55px; + right:-76px; + border:1px solid #ddd; + border-left:0; + font-size:12px; + /* Shadow */ + -moz-box-shadow: 3px 3px 4px #555; + -webkit-box-shadow: 3px 3px 4px #555; + box-shadow: 3px 3px 4px #555; + /* For IE 8 */ + -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#555555')"; + /* For IE 5.5 - 7 */ + filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#555555'); +} diff --git a/context_ui/context_ui_dialog.js b/context_ui/context_ui_dialog.js new file mode 100644 index 0000000..ea294db --- /dev/null +++ b/context_ui/context_ui_dialog.js @@ -0,0 +1,40 @@ +(function ($) { + + Drupal.behaviors.context_ui_dialog = { + attach: function(context) { + var selector = $('#context_ui_dialog-context-ui', context).not('context_ui_dialog-processed'); + + if(selector) { + selector.addClass('context_ui_dialog-processed'); + selector.detach(); + $('#page').prepend(selector); + + var labelOpen = Drupal.t('Select Context'); + var labelClose = Drupal.t('Hide'); + + // Create a tab to show/hide our edit area + var tab = $(''+labelClose+''); + selector.append(tab); + + selector.toggled = false; + var width = $(selector).outerWidth(); + tab.click(function(e){ + if(selector.toggled) { + selector.stop(true, false).animate({'left':0}, 400); + selector.toggled = false; + $(this).text(labelClose); + } else { + selector.stop(true, false).animate({'left':-width-4}, 400); + selector.toggled = true; + $(this).text(labelOpen); + } + }); + + $('#context_ui_dialog-context-ui').show(); + + // Add a class to body + $('body').once().addClass('context-field-editor'); + } + } + }; +})(jQuery); diff --git a/context_ui/export_ui/context.inc b/context_ui/export_ui/context.inc index 968a88b..9dcab78 100644 --- a/context_ui/export_ui/context.inc +++ b/context_ui/export_ui/context.inc @@ -1,6 +1,7 @@ 'administer contexts', 'schema' => 'context', 'menu' => array( 'menu prefix' => 'admin/structure', diff --git a/context_ui/theme/filter.js b/context_ui/theme/filter.js new file mode 100644 index 0000000..82daa1f --- /dev/null +++ b/context_ui/theme/filter.js @@ -0,0 +1,66 @@ +/** + * create a simple search filter thing for a list + */ +(function ($) { + Drupal.Filter = function (list, title, type, parent){ + this.list = list; + this.title = title; + //provide defaults for type and parent so bad things don't happen + if (!type) { var type = '*'; } + this.type = type; + if (!parent) { var parent = list; } + this.parent = parent; + + this.init(); + } + + Drupal.Filter.prototype = { + init : function(){ + this.wrapper = $('
'); + if(this.title){ + this.title = '

' + this.title + '

'; + this.wrapper.append(this.title); + } + this.input = $(''); + this.wrapper.append(this.input); + + $(this.parent).append(this.wrapper); + this.createHandlers(); + }, + createHandlers : function(){ + var self = this; + $(this.input).keyup(function(e){ + self.filter(); + }); + }, + filter : function(){ + //show all first off + $('*', this.list).show(); + //hide ignored items + if(this.input.val()) { + $('*', this.list).not(this.type).hide(); + } + + var regex = new RegExp(this.input.val(), 'i'); + + var self = this; + $(this.type, this.list).each(function(ind, el) { + var string = self.strip(el.innerHTML); + if(!regex.test(string)){ + $(el).hide(); + } else { //show the parent and any labels or whatever in the parent + var parent = $(el).parent().show(); + $('*', parent).not(self.type).show(); + } + }); + }, + strip : function(string){ + var strip = /<([^<|^>]*)>/i; + while(strip.test(string)){ + var matches = string.match(strip); + string = string.replace(strip, ''); + } + return string; + } + }; +})(jQuery); \ No newline at end of file diff --git a/plugins/context_reaction_block.css b/plugins/context_reaction_block.css index de42f0b..30d7834 100644 --- a/plugins/context_reaction_block.css +++ b/plugins/context_reaction_block.css @@ -9,51 +9,69 @@ /** * Browser */ - .context-block-browser .category { display:none; } - - .context-block-item, - .context-block-browser .draggable-placeholder, +.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; - text-shadow:#333 0px 1px 0px; - color:#fff; + color:#333; - padding:5px 4px 4px 5px; + padding:3px 3px 3px 3px; margin:0px 1px 1px 0px; max-width:300px; white-space:nowrap; overflow:hidden; - background:url(context_reaction_block.png) 0px -40px repeat-x; + background:#efefef; + border:1px solid #ddd; position:relative; + border-radius:5px; -moz-border-radius:5px; - -webkit-border-radius:5px; -moz-user-select:none; - -webkit-user-select:none; - } +- -webkit-user-select:none; +} + - .context-block-item span.icon { + .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 { max-width:none; } - .context-block-loading span.icon { + .context-block-loading span.icon { background-position:-20px -80px; float:none; margin:0px auto; - } + } - .context-block-browser .draggable-placeholder { padding:2px 1px 1px 2px; } + .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 { @@ -61,31 +79,45 @@ margin-right:1px; padding-right:9px; float:left; - } + } + - .context-block-addable { cursor: move; } - .context-block-added { display:none !important; } + .context-block-added { display:none !important; } /** * Inline editing elements ============================================ */ -a.context-block-region { display:none; } +div.context-block-region {display: none;} a.context-block { display:none !important; } -body.context-editing .context-block-region-empty a.context-block-region { +body.context-editing div.context-block-region { -moz-border-radius:5px; -webkit-border-radius:5px; background:#666; color:#fff; - opacity:.25; + opacity: 0.5; + -moz-opacity: 0.5; + filter:alpha(opacity=50); display:block; height:40px; - line-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; + padding:; + display:block; + -moz-user-select:none; + -webkit-user-select:none; } body.context-editing .ui-sortable .block { opacity:.25; } @@ -193,3 +225,44 @@ body.context-editing .draggable:hover a.context-block-remove { #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; +} + +.ui-sortable-helper { + max-width: 300px; + max-height: 300px; +} \ No newline at end of file diff --git a/plugins/context_reaction_block.inc b/plugins/context_reaction_block.inc index 8c37186..c433ff5 100644 --- a/plugins/context_reaction_block.inc +++ b/plugins/context_reaction_block.inc @@ -117,6 +117,7 @@ class context_reaction_block extends context_reaction { 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'); @@ -297,6 +298,7 @@ class context_reaction_block extends context_reaction { * Add markup for making a block editable. */ protected function editable_block($block) { + if (!empty($block->content['#markup']) || element_children($block->content)) { $block->content = array( 'content' => $block->content, @@ -308,6 +310,7 @@ class context_reaction_block extends context_reaction { unset($block->content['content']['#contextual_links']); } } + return $block; } @@ -315,6 +318,7 @@ class context_reaction_block extends context_reaction { * 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) || @@ -323,8 +327,17 @@ class context_reaction_block extends context_reaction { global $theme; $regions = system_region_list($theme); $name = isset($regions[$region]) ? $regions[$region] : $region; - $build['context']['#markup'] = "{$name}"; + // The negative weight + sorted will push our region marker to the top of the region + $build['context'] = array( + '#prefix' => "
", + '#markup' => "{$name}" . + "" . t('Add a block here.') . '', + '#suffix' => '
', + '#weight' => -100, + ); + $build['#sorted'] = FALSE; } + return $build; } diff --git a/plugins/context_reaction_block.js b/plugins/context_reaction_block.js index 36933a1..0228fbb 100644 --- a/plugins/context_reaction_block.js +++ b/plugins/context_reaction_block.js @@ -40,6 +40,9 @@ Drupal.behaviors.contextReactionBlock = {attach: function(context) { return false; }); }); + + // Conceal Section title, subtitle and class + $('div.context-block-browser', context).nextAll('.form-item').hide(); }}; /** @@ -75,6 +78,7 @@ DrupalContextBlockForm = function(blockForm) { $(this).parents('div.form-item').eq(0).show(); } }); + }; // make sure we update the state right before submits, this takes care of an @@ -115,6 +119,7 @@ DrupalContextBlockForm = function(blockForm) { $(block).html(""+ text + "" + select + "X"); // 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 var base = "context-blockform-region-"+ region; Drupal.tableDrag[base].makeDraggable(block); $('table#'+base).append(block); @@ -146,295 +151,322 @@ DrupalContextBlockEditor = function(editor) { this.blocks = {}; this.regions = {}; - // Category selector handler. - // Also set to "Choose a category" option as browsers can retain - // form values from previous page load. - $('select.context-block-browser-categories', editor).change(function() { - var category = $(this).val(); - var params = { - containment: 'document', - revert: true, - dropOnEmpty: true, - placeholder: 'draggable-placeholder', - forcePlaceholderSize: true, - helper: 'clone', - appendTo: 'body', - connectWith: ($.ui.version === '1.6') ? ['.ui-sortable'] : '.ui-sortable' - }; - $('div.category', editor).hide().sortable('destroy'); - $('div.category-'+category, editor).show().sortable(params); - }); - $('select.context-block-browser-categories', editor).val(0).change(); - 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($('')); - $(this).prepend($('').click(function() { - $(this).parent ('.block').eq(0).fadeOut('medium', function() { - $(this).remove(); - self.updateBlocks(); +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($('')); + $(this).prepend($('').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'); }); - return false; - })); - }); -}; - -DrupalContextBlockEditor.prototype.initRegions = function(regions) { - this.regions = regions; -}; - -/** - * Update UI to match the current block states. - */ -DrupalContextBlockEditor.prototype.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. - $('#context-block-addable-'+bid, browser).draggable('disable').addClass('context-block-added').removeClass('context-block-addable'); - }); - // 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]; - if ($('#block-'+bid).size() === 0) { - $(this).draggable('enable').removeClass('context-block-added').addClass('context-block-addable'); - } - }); - - // 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'); + $('.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:630, + width:630, + }); -/** - * Live update a region. - */ -DrupalContextBlockEditor.prototype.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 - // jQuery UI 1.6 - // $('div.draggable-placeholder', region).size() === 0 && - // $('div.block:has(a.context-block)', region).size() == 1 && - // $('div.block:has(a.context-block)', region).attr('id') == ui.item.attr('id') - ) { - $(region).addClass('context-block-region-empty'); + //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(); } - break; - } -}; + }); + + //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', this.addToRegion) + } -/** - * Remove script elements while dragging & dropping. - */ -DrupalContextBlockEditor.prototype.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); - } -}; + //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', 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]; + }); -/** - * Add a block to a region through an AHAH load of the block contents. - */ -DrupalContextBlockEditor.prototype.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; - - // Replace item with loading block. - var blockLoading = $('
'); - ui.item.addClass('context-block-added'); - ui.item.after(blockLoading); - ui.sender.append(ui.item); - - $.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(); - }); + // Mark empty regions. + $(this.regions).each(function() { + if ($('.block:has(a.context-block)', this).size() > 0) { + $(this).removeClass('context-block-region-empty'); } else { - blockLoading.fadeOut(function() { $(this).remove(); }); + $(this).addClass('context-block-region-empty'); } }); - } - else if (ui.item.is(':has(a.context-block)')) { - self.updateBlocks(); - } -}; + }, + // 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; + + // Replace item with loading block. + //ui.sender.append(ui.item); + + var blockLoading = $('
'); + 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; -/** - * Update form hidden field with JSON representation of current block visibility states. - */ -DrupalContextBlockEditor.prototype.setState = function() { - var self = this; - - $(this.regions).each(function() { - var region = $('a.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); - } + $(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('
'+ label + '
'); + + // 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); }); - 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. - */ -DrupalContextBlockEditor.prototype.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; }); - } -}; + // Second pass, hook up all regions via connectWith to each other. + $(this.regions).each(function() { + $(this).sortable('option', 'connectWith', ['.ui-sortable']); + }); -/** - * Enable text selection. - */ -DrupalContextBlockEditor.prototype.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'); - } -}; + // 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'); + }); -/** - * Start editing. Attach handlers, begin draggable/sortables. - */ -DrupalContextBlockEditor.prototype.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($('a.context-block-region').parent()); - this.updateBlocks(); - - // First pass, enable sortables on all regions. - $(this.regions).each(function() { - var region = $(this); - var params = { - containment: 'document', - 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'); } - }; - region.sortable(params); - }); + $('a.context_ui_dialog-stop').show(); - // Second pass, hook up all regions via connectWith to each other. - $(this.regions).each(function() { - $(this).sortable('option', 'connectWith', ['.ui-sortable']); - }); + this.regions.sortable('destroy'); - // 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; - } -}; + this.setState(); -/** - * Finish editing. Remove handlers. - */ -DrupalContextBlockEditor.prototype.editFinish = function() { - this.editor.removeClass('context-editing'); - this.enableTextSelect(); - - // 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'); + // Unhack the user agent. + if ($.ui.version === '1.6' && $.browser.safari) { + $.browser.mozilla = false; } - $(this).removeClass('draggable'); - }); - 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); diff --git a/theme/context-block-browser.tpl.php b/theme/context-block-browser.tpl.php index 2359951..69e8a15 100644 --- a/theme/context-block-browser.tpl.php +++ b/theme/context-block-browser.tpl.php @@ -1,17 +1,21 @@
+
+ $module_blocks): ?> -
+ +
+
+ + $block)); ?> + +
+ - $module_blocks): ?> - - -
- - $block)); ?>
- - - - +
+
+
+ +
diff --git a/theme/context_reaction_block.theme.inc b/theme/context_reaction_block.theme.inc index 06c6bbe..b794342 100644 --- a/theme/context_reaction_block.theme.inc +++ b/theme/context_reaction_block.theme.inc @@ -72,7 +72,7 @@ function theme_context_block_script_placeholder($text = '') { function template_preprocess_context_block_browser(&$vars) { $categories = array( '#type' => 'select', - '#options' => array(0 => '<' . t('Choose a category') . '>'), + '#options' => array(0 => '<' . t('All Categories') . '>'), '#attributes' => array('class' => array('context-block-browser-categories')), '#value' => 0, '#size' => 1, @@ -95,8 +95,25 @@ function template_preprocess_context_block_browser(&$vars) { } $blocks[$group][$block->bid] = $block; // Don't call theme('context_block_browser_item') to allow others to alter. } + + //add help text to tell people how to use the block browser + $help_text = array( + '#prefix' => '
', + '#markup' => t('To add a block to the current region, simply click on the block. You may use the category filter to filter by + block type or the search filter to find the block that you wish to add.'), + '#suffix' => '
', + ); + + $filter_label = array( + '#prefix' => '
', + '#markup' => t('Search Filter'), + '#suffix' => '
', + ); + $vars['categories'] = $categories; // Don't call theme('select') here to allow further preprocesses to alter the element. $vars['blocks'] = $blocks; + $vars['help_text'] = $help_text; + $vars['filter_label'] = $filter_label; } /**