Disable Drupal's textarea expander? - drupal

Similar to the question posting form on SO, Drupal adds a draggable expander to the bottom of textareas created through the form api. How can I disable this in a nice manner?

The draggable expander gets added via the behavior defined in 'misc/textearea.js'. From that you can see that it applies to textareas having a class 'resizable'. You can prevent the output of this class if you set the '#resizable' property on a textareas FAPI definition to FALSE (it defaults to TRUE if not explicitly set).
So for your own forms, you can just declare the textareas accordingly. For other forms, youD need to adjust them via hook_form_alter().

A new module called Disable Resizable Textarea was release now.
This is a simple module that add ability to override the default #resizable property of textarea fields. By default, all textareas are resizable. This module allows you to disable this feature on each field.
It is very easy to set up. Just edit the desired field and you will see an "Disable #resizable property of this textarea" option. You can also disable resizable from its summary, if the field is of type "Long text with summary".

body textarea {
resize: none;
}

The simplest, would be to remove the file /misc/textarea.js.
The harder, but probably nicer way is to fix this in either your theme, or in a tiny module.
In your theme, you have two options again:
use a preprocess to remove the textarea.js from the list of javascript files.
use a theme override (yourtheme_textarea) to remove the class resizable-textarea from the rendered HTML. Some information on that in the forums
The option in a module, would be to run a hook_form_alter() to grab any form and run that trough a processor:
/**
* Implementation of hook_form_alter().
*
* Before Drupal 7, there is no way to easily identify form fields that are
* input format enabled. As a workaround, we assign a form #after_build
* processing callback that is executed on all forms after they have been
* completely built, so form elements are in their effective order
* and position already.
*
* #see wysiwyg_process_form()
*/ /**
* Implementation of hook_form_alter().
*
* Before Drupal 7, there is no way to easily identify form fields that are
* input format enabled. As a workaround, we assign a form #after_build
* processing callback that is executed on all forms after they have been
* completely built, so form elements are in their effective order
* and position already.
*
* #see wysiwyg_process_form()
*/
function wysiwyg_form_alter(&$form, &$form_state) {
$form['#after_build'][] = 'wysiwyg_process_form';
// Teaser splitter is unconditionally removed and NOT supported.
if (isset($form['body_field'])) {
unset($form['body_field']['teaser_js']);
}
}
function wysiwyg_process_form(&$form) {
// Iterate over element children; resetting array keys to access last index.
if ($children = array_values(element_children($form))) {
foreach ($children as $index => $item) {
$element = &$form[$item];
// filter_form() always uses the key 'format'. We need a type-agnostic
// match to prevent false positives. Also, there must have been at least
// one element on this level.
if (($item === 'format' || $item === 'signature_format') && $index > 0) {
// Make sure we either match a input format selector or input format
// guidelines (displayed if user has access to one input format only).
if ((isset($element['#type']) && $element['#type'] == 'fieldset') || isset($element['format']['guidelines'])) {
// The element before this element is the target form field.
$field = &$form[$children[$index - 1]];
$extra_class = '';
if (!empty($field['#resizable'])) {
$extra_class = ' wysiwyg-resizable-1';
drupal_add_js('misc/textarea.js');
}
// If we loaded at least one editor, then the 'none' editor will
// handle resizable textareas instead of core.
if (isset($loaded) && !empty($field['#resizable'])) {
$field['#resizable'] = FALSE;
}
}
// If this element is 'format', do not recurse further.
continue;
}
// Recurse into children.
wysiwyg_process_form($element);
}
}
return $form;
}
These examples are from WYSIWYG module, and slightly altered.
In your theme is far simple, but requires a theme that you can override. The module is both performance-wise worse, and a lot more complex. However, it will work on any theme.

There are to ways how to remove resizable textarea in Drupal (7).
1th Place this simple snipped into your theme template.php. Don't forget to rename THEMENAME to your theme name.
/**
* Override of theme('textarea').
* Deprecate misc/textarea.js in favor of using the 'resize' CSS3 property.
*/
function THEMENAME_textarea($variables) {
$element = $variables ['element'];
element_set_attributes($element, array('id', 'name', 'cols', 'rows'));
_form_set_class($element, array('form-textarea'));
$wrapper_attributes = array(
'class' => array('form-textarea-wrapper'),
);
$output = '<div' . drupal_attributes($wrapper_attributes) . '>';
$output .= '<textarea' . drupal_attributes($element ['#attributes']) . '>' . check_plain($element ['#value']) . '</textarea>';
$output .= '</div>';
return $output;
}
2nd Other way is to use another module called Disable resizable textarea.
More info and source.

Related

How to add a Bootstrap grid to the wordpress Editor as a selection or dropdown menu

Problem: I'm looking to expand our WordPress theme(s)/websites to make it easier for our communications team to create posts and pages by adding in Bootstrap rows and columns.
My idea is to create A custom Field type with a selection to add in rows and columns to fit our themes pages.
Has anyone done something like this? We are using Divi Builder but that is a bit complicated for average users and we are not in arush to create a whole new theme for our 30+ websites.
Or would I need to create a custom plugin for that? I'd rather not use a third party plugin for security reasons
So are you wanting output bootstrap markup in your default wordpress editor to make rows and columns etc?
Short answer is no, the wysiwyg editor is only really built for paragraphs, headings, quotes, horizontal rules, lists, images, inline formatting etc...
In order integrate bootstraps block layout markup would require some extra level of builder addon. Elementor definitely could do the job with some super customisation, even ACF flexible content would do it, and i think even WP Gutenberg can do this natively... but would require customisation to use bootstrap markup.
But if you wanted to attempt and utilise the standard wordpress editor (not Gutenberg editor) using the element dropdown (paragraph, headings etc by default).
You could try this, however I recommend loading the same front end bootstrap css into the wysiwyg editor so you can instantly see changes.
Please note this method below is risky as the user would need to understand how bootstraps row/column structure should be formatted. The probability of html markup going wrong is highly likely. Hence using an actual block element builder (like Elementor or ACF) would be a safer choice.
Anyway, see below example of how to customise standard wordpress wysiwyg editor dropdown for wrapping html tags around content.
First load the same front end bootstrap css into the wysiwyg editor...
// editor stylesheet (containing the front end css for the post content)
add_editor_style('dist/css/editor.css');
Now lets add the styleselect dropdown to our wysiwyg editor...
// add the style select dropdown to our wysiwyg editor
add_filter('mce_buttons_2', 'formatting_dropdown');
/**
* #link https://developer.wordpress.org/reference/hooks/mce_buttons_2
* #param $buttons
* #return mixed
*/
function formatting_dropdown($buttons) {
// global post object
global $post;
// if no post return param
if(!$post) return $buttons;
// switch case for post types or type to run this on (page/post)
switch ($post->post_type) {
case 'page':
case 'post';
// reveal the hidden “Styles” dropdown in the advanced toolbar
array_unshift($buttons,'styleselect');
return $buttons;
default;
return $buttons;
}
}
And then add your bootstrap formatting settings using this filter below...
// init filter for handling the style select options
add_filter('tiny_mce_before_init', 'formatting_dropdown_options');
/**
* #link https://developer.wordpress.org/reference/hooks/tiny_mce_before_init/
* #param $mceInit
* #return mixed
*/
function formatting_dropdown_options($mceInit) {
// global post
global $post;
// if no post return param
if(!$post) return $mceInit;
// switch case for post type (page/post)
switch ($post->post_type) {
case 'page':
case 'post';
// new style array
$style_formats = [
[
'title' => 'row',
'block' => 'div',
'classes' => 'row'
],
[
'title' => 'col',
'block' => 'div',
'classes' => 'col'
]
];
// bs5 breakpoints
$breakpoints = ['xs','sm','md','lg','xl','xxl'];
// bs5 column grid
$grid = 12;
// add bs5 column classes to $style_formats array
foreach ($breakpoints as $breakpoint) {
foreach (range(1, $grid) as $column) {
$style_formats[] = [
'title' => $breakpoint === 'xs' ? 'col-' . $column : 'col-' . $breakpoint . '-' . $column,
'block' => 'div',
'classes' => $breakpoint === 'xs' ? 'col-' . $column : 'col-' . $breakpoint . '-' . $column
]
}
}
// override style format with new style formats
$mceInit['style_formats'] = json_encode($style_formats);
// init array
return $mceInit;
break;
default;
// init array
return $mceInit;
}
}

Display drupal node edit preview title instead of just "Preview"

How to change the node preview title to be displayed instead of just "Preview"?
This is a way to solve your problem in your custom module
/**
* implements hook_form_BASE_FORM_ID_alter
* the form id that will build the node preview is page_node_form
* #param $form
* #param $form_state
*/
function yourmodulename_form_page_node_form_alter( $form, $form_state ){
if( !empty( $form_state['node']->in_preview ) ){
// security hint: do not pass the PASS_THROUGH param to the drupal_set_title
// because the node title may contain some xss. Without this parameter the
// drupal_set_title will check for xss and remove them if present
drupal_set_title(t('Preview') . ' ' . $form['#node']->title );
}
}
Here how to hack core to modify the title (quick and easy way) but better would be to override via a custom module (perhaps somebody else can post please).
In /modules/node/node.pages.inc add $node->title within drupal_set_title(t('Preview'), PASS_THROUGH);
like so:
// Display a preview of the node.
if (!form_get_errors()) {
$cloned_node->in_preview = TRUE;
$output = theme('node_preview', array('node' => $cloned_node));
unset($cloned_node->in_preview);
}
drupal_set_title(t('Preview: '.$node->title), PASS_THROUGH);

How to add a body class for the current node's taxonomy to a Drupal 7 theme

Does anyone know how or can guide me in the right direction on how to add a body css class for the current node's taxonomy term? i.e. <body class="term-dogs"> where "dogs" is the taxonomy term name. It could also be just the term ID. Either way is fine I just need a solution. This will be for a Drupal 7 zen sub-theme
This answer took longer than I expected to figure out. The hard part was collecting the terms on the node, since All taxonomy functions relating to nodes have been removed or refactored. Ultimately, page 355 of Pro Drupal 7 Development saved the day with a snippet that does the job previously handled by taxonomy_node_get_terms.
Below is the code that worked for me (look for the part that says "MAGIC BEGINS HERE"). Assuming you're creating a sub-theme of Zen, you'll want to move this to your sub-theme's template.php file and rename it to YOURSUBTHEMENAME_preprocess_html:
/**
* Override or insert variables into the html template.
*
* #param $vars
* An array of variables to pass to the theme template.
* #param $hook
* The name of the template being rendered ("html" in this case.)
*/
function zen_preprocess_html(&$vars, $hook) {
// If the user is silly and enables Zen as the theme, add some styles.
if ($GLOBALS['theme'] == 'zen') {
include_once './' . drupal_get_path('theme', 'zen') . '/zen-internals/template.zen.inc';
_zen_preprocess_html($vars, $hook);
}
// Classes for body element. Allows advanced theming based on context
// (home page, node of certain type, etc.)
if (!$vars['is_front']) {
// Add unique class for each page.
$path = drupal_get_path_alias($_GET['q']);
// Add unique class for each website section.
list($section, ) = explode('/', $path, 2);
if (arg(0) == 'node') {
if (arg(1) == 'add') {
$section = 'node-add';
}
elseif (is_numeric(arg(1)) && (arg(2) == 'edit' || arg(2) == 'delete')) {
$section = 'node-' . arg(2);
}
// MAGIC BEGINS HERE
$node = node_load(arg(1));
$results = field_view_field('node', $node, 'field_tags', array('default'));
foreach ($results as $key => $result) {
if (is_numeric($key)) {
$vars['classes_array'][] = strtolower($result['#title']);
}
}
// MAGIC ENDS HERE
}
$vars['classes_array'][] = drupal_html_class('section-' . $section);
}
if (theme_get_setting('zen_wireframes')) {
$vars['classes_array'][] = 'with-wireframes'; // Optionally add the wireframes style.
}
// Store the menu item since it has some useful information.
$vars['menu_item'] = menu_get_item();
switch ($vars['menu_item']['page_callback']) {
case 'views_page':
// Is this a Views page?
$vars['classes_array'][] = 'page-views';
break;
case 'page_manager_page_execute':
case 'page_manager_node_view':
case 'page_manager_contact_site':
// Is this a Panels page?
$vars['classes_array'][] = 'page-panels';
break;
}
}
I needed to know how to do this and Matt V's solution worked perfectly. I made a couple of additions to his work. I called drupal_html_class which replaces spaces and invalid characters. And I added in the term ID to allow you to target a term even if the name of the term changes.
// MAGIC BEGINS HERE
$node = node_load(arg(1));
$results = field_view_field('node', $node, 'field_tags', array('default'));
foreach ($results as $key => $result) {
if (is_numeric($key)) {
// Call drupal_html_class to make safe for a css class (remove spaces, invalid characters)
$vars['classes_array'][] = "taxonomy-" . strtolower(drupal_html_class( $result['#title']) );
// Add taxonomy ID. This will allow targeting of the taxonomy class even if the title changes
$vars['classes_array'][] = "taxonomy-id-" . $result['#options']['entity']->tid ;
}
}
// MAGIC ENDS HERE
Not sure what you mean with that body tag, but the classes on the node are generated here:
http://api.drupal.org/api/drupal/modules--node--node.module/function/template_preprocess_node/7
You can add more by implementing yourmodule_preprocess_node($vars) and then add whatever you want to $vars['classes_array']

Is it possible to *optionally* override a theme in Drupal 6?

I want to override the theming of only one (custom) menu. I can do this with phptemplate_menu_tree() but - of course - it overrides the rendering of all menus.
I've tried returning FALSE (an obvious technique IMO) if the menu is not the specific one I want to override - but this doesn't cause the overridden theme function to be called.
My only alternative (when the menu is anything other than the specific one) is to call the overridden function from within phptemplate_menu_tree() - but this seems to defeat the whole point of the override system, since the default rendering function will be hard-coded therein.
I hope the explanation is clear, and any help is greatly appreciated - tks.
UPDATE
For the sake of future reference, I'll explain how I solved this.
First off, the menu rendering starts with this function in menu.module:
function menu_block($op = 'list', $delta = 0) {
$menus = menu_get_menus();
// The Navigation menu is handled by the user module.
unset($menus['navigation']);
if ($op == 'list') {
$blocks = array();
foreach ($menus as $name => $title) {
// Default "Navigation" block is handled by user.module.
$blocks[$name]['info'] = check_plain($title);
// Menu blocks can't be cached because each menu item can have
// a custom access callback. menu.inc manages its own caching.
$blocks[$name]['cache'] = BLOCK_NO_CACHE;
}
return $blocks;
}
else if ($op == 'view') {
$data['subject'] = check_plain($menus[$delta]);
$data['content'] = menu_tree($delta);
return $data;
}
}
If you only want to override how individual item (links) are rendered then you can use the theme system (there are loads of references on how do this) - but if you want complete control on how the entire menu tree is rendered (for example, wrapping the output in nested DIVs so it can be centred on the page) then there is no way to override menu_block().
Therefore, I removed the menu I wanted to render differently from the administer blocks page (site building->blocks) and rendered the menu directly in my page.tpl.php using code something like this: (angle brackets removed)
$m = menu_tree_page_data('my-menu-id');
$o = "DIV";
foreach($m as $k => $v){
$o .= "SPAN {$v['link']['title']} /SPAN";
}
$o .= "/DIV";
echo $o;
I hope this helps.
I've had mixed success doing template.php menu overrides to force CSS classes and ids or HTML into the output.
You could make use of Block Theme when enabling the menu as a block, but I've never tried it.
http://drupal.org/project/blocktheme
If you want to tackle the template way, here are the zen menu override funcitons...
function zen_menu_item_link($link) {
if (empty($link['localized_options'])) {
$link['localized_options'] = array();
}
// If an item is a LOCAL TASK, render it as a tab
if ($link['type'] & MENU_IS_LOCAL_TASK) {
$link['title'] = '<span class="tab">' . check_plain($link['title']) . '</span>';
$link['localized_options']['html'] = TRUE;
}
return l($link['title'], $link['href'], $link['localized_options']);
}
function zen_menu_local_tasks() {
$output = '';
if ($primary = menu_primary_local_tasks()) {
$output .= '<ul class="tabs primary clear-block">' . $primary . '</ul>';
}
if ($secondary = menu_secondary_local_tasks()) {
$output .= '<ul class="tabs secondary clear-block">' . $secondary . '</ul>';
}
return $output;
}
You could use sections module, or look at how it switches theme for certain menu-items.
what I did was register a new theme function in my template.php called primary_links (because I wanted to only customize this menu in certain way) created the function mytheme_primary_links() in my template.php refreshed the cache so Drupal would add my theme function to the system then changed theme function on primary_links from links to my custom theme function primary_links - this allows me to customize only this 1 menu - could you do this and hook into where ever to change the theme function being called for your links?
Chris

How do I alter the #weight of the content generated by the upload.module?

On my Drupal powered website, I want to list available downloads at the top of a node page (within a narrow float:right <div>), not at the bottom where they normally appear.
Within my theme, I've overridden the theme_upload_attachments() function to generate a <div> of width 40%, but this is showing up at the bottom of the page.
Within the upload.module file is code that controls where the attachments are listed on the page:
// function upload_nodeapi(), line #284 of upload.module
$node->content['files'] = array(
'#value' => theme('upload_attachments', $node->files),
'#weight' => 50,
);
If I manually hack this #weight to -1, my custom list of attachments shows where I want, floating at the righthand side of the top of the content area.
However, I don't want to manually hack the core file upload.module, as my changes will be lost next time I apply an upgrade (say, for a security patch).
How/Where do I modify the #weight of content['files'] within my theme code?
Or, am I going about this the wrong way?
You'll need a module to do this, not just a theme. A module can implement hook_nodeapi(), which will give it a chance to change the contents of that $node->content array before it's rendered. If your module is named 'upload_tweaker' for example, you'd use the following function:
function upload_tweaker_nodeapi(&$node, $op) {
if ($op == 'view') {
$node->content['files']['#weight'] = -1;
}
}
Each module gets a crack at changing the node during this 'nodeapi' event; if you want to change the stuff that's added by one module, you need to make sure that your module loads after it. This can be done by naming it something like 'zzz', or by changing its "weight" field in the system table of your site's database. Modules can be weighted just like form elements.
api.drupal.org has more information.
For those who uses CCK and want to alter body weight:
CCK module uses pre_render function
/**
* Pre-render callback to adjust weights of non-CCK fields.
*/
function content_alter_extra_weights($elements) {
if (isset($elements['#content_extra_fields'])) {
foreach ($elements['#content_extra_fields'] as $key => $value) {
// Some core 'fields' use a different key in node forms and in 'view'
// render arrays. Check we're not on a form first.
if (!isset($elements['#build_id']) && isset($value['view']) && isset($elements[$value['view']])) {
$elements[$value['view']]['#weight'] = $value['weight'];
}
elseif (isset($elements[$key])) {
$elements[$key]['#weight'] = $value['weight'];
}
}
}
return $elements;
}
So due to this callback you are not able to alter weight using normal behavior.
You should do this:
function YOUR_MODULE_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
// Only for node pages.
if ($op == 'view' && $a4) {
$body_weight = 15 // Any weight.
$node->content['#content_extra_fields']['body']['weight'] = $body_weight; // This value CCK module will use to alter body weight in the callback from above.
}
}

Resources