format]) && !$reset) { return $shortcodes_enabled[$format->format]; } $shortcodes_enabled[$format->format] = array(); $shortcodes = shortcode_list_all($reset); $filters = filter_list_format($format->format); if (empty($filters['shortcode'])) { return array(); } // Run through all Shortcodes defined. foreach ($filters['shortcode']->settings as $name => $enabled) { if ($enabled) { $shortcodes_enabled[$format->format][$name] = $shortcodes[$name]; } } return $shortcodes_enabled[$format->format]; } /** * Implements hook_filter_info(). */ function shortcode_filter_info() { $filters['shortcode'] = array( 'title' => t('Shortcodes'), 'description' => t('Provides WP like shortcodes to this text format.'), 'process callback' => '_shortcode_process', 'settings callback' => '_shortcode_settings_form', 'tips callback' => '_shortcode_filter_tips', ); $filters['shortcode_text_corrector'] = array( 'title' => t('Shortcodes - html corrector'), 'description' => t('Trying to correct the html around shortcodes. Enable only if you using wysiwyg editor.'), 'process callback' => '_shortcode_postprocess_text', ); return $filters; } /** * Provides filter tips callback. */ function _shortcode_filter_tips($filter, $format, $long = FALSE) { $shortcodes = shortcode_list_all_enabled($format); $tips = array(); foreach ($filter->settings as $name => $enabled) { if ($enabled && !empty($shortcodes[$name]['tips callback']) && is_string($shortcodes[$name]['tips callback']) && function_exists($shortcodes[$name]['tips callback'])) { $tips[] = call_user_func_array($shortcodes[$name]['tips callback'], array($format, $long)); } } return theme('item_list', array( 'title' => t('Shortcodes usage'), 'items' => $tips, 'type' => 'ol', ) ); } /** * Provides settings form form Shortcodes enable. */ function _shortcode_settings_form($form, &$form_state, $filter, $format, $defaults) { $settings = array(); $filter->settings += $defaults; $shortcodes = shortcode_list_all(); foreach ($shortcodes as $key => $shortcode) { $settings[$key] = array( '#type' => 'checkbox', '#title' => t('Enable %name shortcode', array('%name' => $shortcode['title'])), '#default_value' => NULL, '#description' => isset($shortcode['description']) ? $shortcode['description'] : t('Enable or disable this shortcode in this input format'), ); if (!empty($filter->settings[$key])) { $settings[$key]['#default_value'] = $filter->settings[$key]; } elseif (!empty($defaults[$key])) { $settings[$key]['#default_value'] = $defaults[$key]; } } return $settings; } /** * Implements small tags cache. */ function _shortcode_tags($tags = NULL) { $shortcodes = &drupal_static(__FUNCTION__, array()); if ($tags) { $shortcodes = $tags; return TRUE; } return $shortcodes; } /** * Checking the given tag is valid Shortcode macro or not. * * @param string $tag * The tag name. * * @return bool * Returns TRUE if the given $tag is valid macro. */ function shortcode_is_tag($tag) { $tags = _shortcode_tags(); if (isset($tags[$tag])) { return TRUE; } return FALSE; } /** * Processes the Shortcodes according to the text and the text format. */ function _shortcode_process($text, $filter) { $shortcodes = shortcode_list_all(); $shortcodes_enabled = array(); foreach ($filter->settings as $name => $value) { if ($value && !empty($shortcodes[$name]['process callback'])) { $shortcodes_enabled[$name] = array( 'function' => $shortcodes[$name]['process callback'], ); } } if (empty($shortcodes_enabled)) { return $text; } // Save the Shortcodes in the local cache. _shortcode_tags($shortcodes_enabled); // Processing recursively, now embeding tags within other tags is supported! $chunks = preg_split('!(\[{1,2}.*?\]{1,2})!', $text, -1, PREG_SPLIT_DELIM_CAPTURE); $heap = array(); $heap_index = array(); foreach ($chunks as $c) { if (!$c) { continue; } $escaped = FALSE; if ((substr($c, 0, 2) == '[[') && (substr($c, -2, 2) == ']]')) { $escaped = TRUE; // Checks media tags, eg: [[{ }]]. if ((substr($c, 0, 3) != '{') && (substr($c, -3, 1) != '}')) { // Removes the outer []. $c = substr($c, 1, -1); } } // Decide this is a Shortcode tag or not. if (!$escaped && ($c[0] == '[') && (substr($c, -1, 1) == ']')) { // The $c maybe contains Shortcode macro. // This is maybe a self-closing tag. // Removes outer []. $original_text = $c; $c = substr($c, 1, -1); $c = trim($c); $ts = explode(' ', $c); $tag = array_shift($ts); $tag = trim($tag, '/'); if (!isset($shortcodes_enabled[$tag])) { // The current tag is not enabled. array_unshift($heap_index, '_string_'); array_unshift($heap, $original_text); } elseif (substr($c, -1, 1) == '/') { // Processes a self closing tag, - it has "/" at the end- /* * The exploded array elements meaning: * 0 - the full tag text? * 1/5 - An extra [] to allow for escaping Shortcodes with double [[]]. * 2 - The Shortcode name. * 3 - The Shortcode argument list. * 4 - The content of a Shortcode when it wraps some content. */ $m = array( $c, '', $tag, implode(' ', $ts), NULL, '', ); array_unshift($heap_index, '_string_'); array_unshift($heap, _shortcode_process_tag($m)); // In shortcode can be used another Format with differents shortcodes, so restore the cache _shortcode_tags($shortcodes_enabled); } elseif ($c[0] == '/') { // Indicate a closing tag, so we process the heap. $closing_tag = substr($c, 1); $process_heap = array(); $process_heap_index = array(); $found = FALSE; // Get elements from heap and process. do { $tag = array_shift($heap_index); $heap_text = array_shift($heap); if ($closing_tag == $tag) { // Process the whole tag. $m = array( $tag . ' ' . $heap_text, '', $tag, $heap_text, implode('', $process_heap), '', ); $str = _shortcode_process_tag($m); // In shortcode can be used another Format with differents shortcodes, so restore the cache _shortcode_tags($shortcodes_enabled); array_unshift($heap_index, '_string_'); array_unshift($heap, $str); $found = TRUE; } else { array_unshift($process_heap, $heap_text); array_unshift($process_heap_index, $tag); } } while (!$found && $heap); if (!$found) { foreach ($process_heap as $val) { array_unshift($heap, $val); } foreach ($process_heap_index as $val) { array_unshift($heap_index, $val); } } } else { // This is a starting tag. Put it to the heap. array_unshift($heap_index, $tag); array_unshift($heap, implode(' ', $ts)); } // If escaped or not a Shortcode. } else { // Maybe not found a pair? array_unshift($heap_index, '_string_'); array_unshift($heap, $c); } // End of foreach. } return (implode('', array_reverse($heap))); } /** * Provides Html corrector for wysiwyg editors. * * Correcting p elements around the divs. There are no
so remove them. */ function _shortcode_postprocess_text($text, $filter) { $patterns = array( '|#!#|is', '!
( |\s)*(<\/*div>)!is', '!
( |\s)*(