syntaxhighlighter.module in Syntax Highlighter 7.2
Same filename and directory in other branches
Syntax highlight code using the Syntaxhighlighter javascript library. See http://alexgorbatchev.com/wiki/SyntaxHighlighter
@author: Matthew Young <www.hddigitalworks.com/contact>
File
syntaxhighlighter.moduleView source
<?php
/**
* @file
* Syntax highlight code using the Syntaxhighlighter javascript library.
* See http://alexgorbatchev.com/wiki/SyntaxHighlighter
*
* @author: Matthew Young <www.hddigitalworks.com/contact>
*/
/**
* Inject syntaxhighlighter on every page except the listed pages.
*/
define('SYNTAXHIGHLIGHTER_INJECT_EXCEPT_LISTED', 0);
/**
* Inject syntaxhighlighter on only the listed pages.
*/
define('SYNTAXHIGHLIGHTER_INJECT_IF_LISTED', 1);
/**
* Inject syntaxhighlighter if the associated PHP code returns TRUE.
*/
define('SYNTAXHIGHLIGHTER_INJECT_PHP', 2);
define('SYNTAXHIGHLIGHTER_PHP_PERMISSION', 'use PHP for syntaxhighlighter js/css code inject control');
/**
* Use a completely none sense word for replacement when filtering so there is
* absolutely no chance this will conflict with something in content text
*/
define('SYNTAXHIGHLGHTER_TAG_STRING', '-_sYnTaXhIgHlIgHtEr_-');
/**
* Implements hook_permission().
*/
function syntaxhighlighter_permission() {
return array(
SYNTAXHIGHLIGHTER_PHP_PERMISSION => array(
'title' => t('Use PHP for syntaxhighlighter js/css code inject control'),
'restrict access' => TRUE,
),
);
}
/**
* Menu for admin settings page
*/
function syntaxhighlighter_menu() {
$items['admin/config/content/syntaxhighlighter'] = array(
'title' => 'Syntax highlighter',
'description' => 'Configure syntax highlighter',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'syntaxhighlighter_settings_form',
),
'access arguments' => array(
'administer modules',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'syntaxhighlighter.admin.inc',
);
return $items;
}
function syntaxhighlighter_help($path, $arg) {
switch ($path) {
case 'admin/help#syntaxhighlighter':
return _syntaxhighlighter_filter_tips(0, 0, TRUE);
}
}
function syntaxhighlighter_init() {
if (!_syntaxhighlighter_page_match()) {
return;
}
$lib_location = _syntaxhighlighter_get_lib_location();
$styles_path = $lib_location . '/styles/';
$scripts_path = $lib_location . '/scripts/';
$js_options = array(
'type' => 'file',
'group' => JS_DEFAULT,
'every_page' => TRUE,
);
drupal_add_css($styles_path . 'shCore.css');
$theme = variable_get('syntaxhighlighter_theme', 'shThemeDefault.css');
drupal_add_css($styles_path . $theme);
drupal_add_js($scripts_path . 'shCore.js', $js_options);
if (variable_get('syntaxhighlighter_legacy_mode', 0)) {
drupal_add_js($scripts_path . 'shLegacy.js', $js_options);
}
if (variable_get('syntaxhighlighter_use_autoloader', FALSE)) {
drupal_add_js($scripts_path . 'shAutoloader.js', $js_options);
drupal_add_js(_syntaxhighlighter_file_directory_path() . '/syntaxhighlighter.autoloader.js', $js_options);
$settings['useAutoloader'] = TRUE;
}
else {
$enabled_languages = variable_get('syntaxhighlighter_enabled_languages', array(
'shBrushPhp.js',
));
foreach ($enabled_languages as $lang) {
if (!empty($lang)) {
drupal_add_js($scripts_path . $lang, $js_options);
}
}
}
$tag_name = variable_get('syntaxhighlighter_tagname', 'pre');
if ($tag_name !== 'pre') {
$settings['tagName'] = $tag_name;
}
if (file_exists($scripts_path . 'clipboard.swf')) {
$settings['clipboard'] = base_path() . $scripts_path . 'clipboard.swf';
}
if (variable_get('syntaxhighlighter_legacy_mode', 0)) {
$settings['legacyMode'] = TRUE;
}
if (isset($settings)) {
drupal_add_js(array(
'syntaxhighlighter' => $settings,
), 'setting');
}
if ($defaultExpression = variable_get('syntaxhighlighter_default_expressions', '')) {
drupal_add_js($defaultExpression, 'inline');
}
drupal_add_js(drupal_get_path('module', 'syntaxhighlighter') . '/syntaxhighlighter.min.js', array(
'type' => 'file',
'scope' => 'footer',
'group' => JS_DEFAULT,
'every_page' => TRUE,
));
}
function _syntaxhighlighter_page_match() {
$inject = variable_get('syntaxhighlighter_inject', SYNTAXHIGHLIGHTER_INJECT_EXCEPT_LISTED);
$pages = variable_get('syntaxhighlighter_pages', "admin\nadmin/*\nuser\nuser/*\nimce\nimce/*\n");
if ($inject != SYNTAXHIGHLIGHTER_INJECT_PHP) {
$path = drupal_get_path_alias($_GET['q']);
// Compare with the internal and path alias (if any).
$page_match = drupal_match_path($path, $pages);
if ($path != $_GET['q']) {
$page_match = $page_match || drupal_match_path($_GET['q'], $pages);
}
return !($inject xor $page_match);
}
else {
// if the PHP module is not enabled, we just return FALSE
// which just ends up disabling the syntaxhighlighter
return function_exists('php_eval') && php_eval($pages);
}
}
function syntaxhighlighter_modules_disabled($modules) {
if (in_array('php', $modules) && variable_get('syntaxhighlighter_inject', SYNTAXHIGHLIGHTER_INJECT_EXCEPT_LISTED) == SYNTAXHIGHLIGHTER_INJECT_PHP) {
drupal_set_message(t('The "%syntaxhighlighter" module is currently configured to use PHP for js/css code inject control, disabling the "%module_name" module will effectively turn off syntax highlighting on all pages.', array(
'%syntaxhighlighter' => t('Syntax highlighter'),
'%module_name' => t('PHP filter'),
)), 'warning');
}
}
/**
* Implements hook_filter_info()
*
* declare the syntaxhighlighter filter
*/
function syntaxhighlighter_filter_info() {
$filters['syntaxhighlighter'] = array(
'title' => t('Syntax highlighter'),
'description' => t('Process syntax highlighter filter code block'),
'tips callback' => '_syntaxhighlighter_filter_tips',
'prepare callback' => '_syntaxhighlighter_do_filter_prepare',
'process callback' => '_syntaxhighlighter_do_filter_process',
'cache' => TRUE,
);
return $filters;
}
function _syntaxhighlighter_filter_tips($filter, $format, $long = FALSE) {
$tag_name = variable_get('syntaxhighlighter_tagname', 'pre');
$tip = t('Syntax highlight code surrounded by the <code>!ex0</code> tags, where !lang is one of the following language brushes: %brushes.', array(
'!ex0' => "<{$tag_name} class=\"brush: <i>lang</i>\">...</{$tag_name}>",
'!lang' => '<i>lang</i>',
'%brushes' => implode(', ', _syntaxhighlighter_get_enabled_language_brushes()),
));
if ($long) {
$tip .= ' ' . t('See <a href="!url0">the SyntaxHighlighter javascript library site</a> for additional helps.', array(
'!url0' => 'http://alexgorbatchev.com/',
));
}
return $tip;
}
/**
* @return an array of all enabled language brushes
*/
function _syntaxhighlighter_get_enabled_language_brushes() {
$brushes =& drupal_static(__FUNCTION__);
if (!isset($brushes)) {
$brushes = array();
foreach (variable_get('syntaxhighlighter_enabled_languages', array(
'shBrushPhp.js',
)) as $val) {
if ($val) {
$brushes[] = strtolower(substr(substr($val, 7), 0, -3));
}
}
}
return $brushes;
}
/**
* Escape the content text in preparation for filtering:
*
* - change all syntaxhighlighter <pre> tag pairs to {-_sYnTaXhIgHlIgHtEr_-}
* {/-_sYnTaXhIgHlIgHtEr_-} pair (so other filters would not mess with them
*
* Precondition: all the open/close tags much match because search is done on
* pair by pair basis. If match is not even, do nothing.
*
* All HTML tags and entities inside the SyntaxHighlighter must be properly
* escape. For example, if you show HTML code, change
*
* - '<' to '<': e.g. <pre> -> <pre>, <html> -> <html>
* - neutralize & in entity: e.g.: > -> &gt;
*
* @param string $text
* the content text to be filtered
* @return
* the escape content text
*/
function _syntaxhighlighter_do_filter_prepare($text) {
$tag_name = variable_get('syntaxhighlighter_tagname', 'pre');
$pattern = "#<{$tag_name}\\s*([^>]*)>|</\\s*{$tag_name}>#";
preg_match_all($pattern, $text, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
$output = '';
$at = 0;
$n = count($matches);
// do nothing if open/close tag match is not even
if ($n % 2) {
return $text;
}
for ($i = 0; $i < $n;) {
$open_tag = $matches[$i++];
$close_tag = $matches[$i++];
if (strpos($open_tag[1][0], 'brush:')) {
$output .= substr($text, $at, $open_tag[0][1] - $at);
$begin = $open_tag[0][1] + strlen($open_tag[0][0]);
$length = $close_tag[0][1] - $begin;
$output .= '{' . SYNTAXHIGHLGHTER_TAG_STRING . ' ' . $open_tag[1][0] . '}' . substr($text, $begin, $length) . '{/' . SYNTAXHIGHLGHTER_TAG_STRING . '}';
$at = $close_tag[0][1] + strlen($close_tag[0][0]);
}
}
$output .= substr($text, $at);
return $output;
}
/**
* Revert back to <pre> tag
*/
function _syntaxhighlighter_do_filter_process($text) {
$patterns = array(
'#{' . SYNTAXHIGHLGHTER_TAG_STRING . ' ([^}]+)}#',
'#{/' . SYNTAXHIGHLGHTER_TAG_STRING . '}#',
);
$tag_name = variable_get('syntaxhighlighter_tagname', 'pre');
$replacements = array(
"<{$tag_name} \$1>",
"</{$tag_name}>",
);
return preg_replace($patterns, $replacements, $text);
}
/**
* Validate on the node input text to be sure there is no bad
* {syntaxhighlighter} tags
*/
function syntaxhighlighter_node_validate($node, $form, &$form_state) {
if (isset($node->body)) {
foreach ($node->body as $lang => $v) {
if (_syntaxhighlighter_format_has_syntaxhighlighter_filter(isset($v[0]['format']) ? $v[0]['format'] : filter_fallback_format())) {
if (!empty($v[0]['summary'])) {
_syntaxhighlighter_validate_input("body][{$lang}][0][summary", $v[0]['summary']);
}
_syntaxhighlighter_validate_input("body][{$lang}][0][value", $v[0]['value']);
}
}
}
}
/**
* Install custom comment validate function
*/
function syntaxhighlighter_form_comment_form_alter(&$form, &$form_state, $form_id) {
$form['#validate'][] = '_syntaxhighlighter_comment_validate';
}
/**
* Validate on comment input text to be sure there is no bad
* {syntaxhighlighter} tags
*/
function _syntaxhighlighter_comment_validate($form, &$form_state) {
if (isset($form_state['values']['comment_body'])) {
foreach ($form_state['values']['comment_body'] as $lang => $v) {
if (_syntaxhighlighter_format_has_syntaxhighlighter_filter(isset($v[0]['format']) ? $v[0]['format'] : filter_fallback_format())) {
_syntaxhighlighter_validate_input("comment_body][{$lang}][0][value", $v[0]['value']);
}
}
}
}
/**
* Check for error with syntaxhighlighter input
*
* @param string $field
* what input field are we checking? We do form_set_error on this if
* any error is found
* @param string $text
* the input text to check for
*/
function _syntaxhighlighter_validate_input($field, $text) {
$errors = array();
$tag_name = variable_get('syntaxhighlighter_tagname', 'pre');
// check for balance open/close tags
preg_match_all("#<{$tag_name}\\s*[^>]*>#", $text, $matches_open);
preg_match_all("#</\\s*{$tag_name}\\s*>#", $text, $matches_close);
if (count($matches_open[0]) != count($matches_close[0])) {
$errors[] = t('Unbalanced !tag tags.', array(
'!tag' => "<{$tag_name}>",
));
}
// make sure no nesting
preg_match_all("#<{$tag_name}\\s*[^>]*>.*</\\s*{$tag_name}\\s*>#sU", $text, $matches_pair);
if (count($matches_pair[0]) != count($matches_open[0]) || count($matches_pair[0]) != count($matches_close[0])) {
$errors[] = t('!tag tags cannot be nested.', array(
'!tag' => "<{$tag_name}>",
));
}
if (!empty($errors)) {
form_set_error($field, implode(' ', $errors));
}
}
/**
* @return the directory path where the syntaxhighlighter js lib is installed, NULL if not found
*/
function _syntaxhighlighter_get_lib_location() {
$result = variable_get('syntaxhighlighter_lib_location', NULL);
if (!$result) {
$result = _syntaxhighlighter_scan_lib_location();
// library location may have changed, recreate the setup script if the lib
// is found
if ($result) {
variable_set('syntaxhighlighter_lib_location', $result);
_syntaxhighlighter_setup_autoloader_script();
}
}
return $result;
}
/**
* Locate the syntaxhighlighter js library. The library must be placed in a
* directory named "syntaxhighlighter" in one of the following locations:
* 1) standard library paths provided by the "libraries" module (if installed)
* 2) the syntaxhighlighter module
* 3) sites/all/libraries/syntaxhighlighter
* 4) sites/[sitename]/libraries/syntaxhighlighter
* 5) under the install profile libraries directory
* @return the file location of the js lib or NULL if not found
*/
function _syntaxhighlighter_scan_lib_location() {
$directories = array();
if (module_exists('libraries')) {
$directories[] = libraries_get_path('syntaxhighlighter');
}
$directories[] = drupal_get_path('module', 'syntaxhighlighter') . "/syntaxhighlighter";
$directories[] = 'sites/all/libraries/syntaxhighlighter';
// Mult-site specific location.
$directories[] = conf_path() . '/libraries/syntaxhighlighter';
// When this function is called during Drupal's initial installation process,
// the name of the profile that is about to be installed is stored in the
// global $profile variable. At all other times, the regular system variable
// contains the name of the current profile, and we can call variable_get()
// to determine the profile.
global $profile;
if (!isset($profile)) {
$profile = variable_get('install_profile', 'default');
}
$directories[] = "profiles/{$profile}/libraries/syntaxhighlighter";
foreach ($directories as $d) {
if (is_file($d . "/scripts/shCore.js")) {
return $d;
}
}
return NULL;
}
/**
* Create the autoload setup script file. Must call this whenever lib
* location and/or the enable brushes change. Make sure never call this
* if the js lib is not found
*/
function _syntaxhighlighter_setup_autoloader_script() {
$path = 'public://syntaxhighlighter.autoloader.js';
if (variable_get('syntaxhighlighter_use_autoloader', FALSE)) {
// use variable_get() instead of _syntaxhighlighter_get_lib_location()
// because this function is called only if the lib location is found
$script_path = base_path() . variable_get('syntaxhighlighter_lib_location', NULL) . '/scripts/';
$script_data = <<<__HERE__
/*
* This file is generated by the Syntaxhighlighter module
*/
__HERE__;
$script_data .= "\nfunction syntaxhighlighterAutoloaderSetup() {\n SyntaxHighlighter.autoloader(\n";
$need_ending = FALSE;
$brushes = variable_get('syntaxhighlighter_enabled_languages', array(
'shBrushPhp.js',
));
foreach ($brushes as $b) {
if ($b) {
if ($need_ending) {
$script_data .= ",\n";
}
$alias = strtolower(substr(substr($b, 7), 0, -3));
$script_data .= " '{$alias} {$script_path}{$b}'";
$need_ending = TRUE;
}
}
$script_data .= "\n);\n}\n";
file_unmanaged_save_data($script_data, $path, FILE_EXISTS_REPLACE);
}
else {
if (file_exists($path)) {
file_unmanaged_delete($path);
}
}
}
/**
* This does the same thing as the old D6 file_directory_path() which
* is to give the default 'files' directory path relative the the web root
*
* @return a string containing the path to the site's 'files' directory
*/
function _syntaxhighlighter_file_directory_path() {
return variable_get('file_public_path', conf_path() . '/files');
}
function _syntaxhighlighter_format_has_syntaxhighlighter_filter($format_id) {
return array_key_exists('syntaxhighlighter', filter_list_format($format_id));
}
/**
* Implements hook_libraries_info().
*/
function syntaxhighlighter_libraries_info() {
$libraries['syntaxhighlighter'] = array(
// Only used in administrative UI of Libraries API.
'name' => 'Syntax Highlighter',
'vendor url' => 'http://alexgorbatchev.com/SyntaxHighlighter/',
'download url' => 'http://alexgorbatchev.com/SyntaxHighlighter/download/',
'download' => array(
'type' => 'file',
'url' => 'http://alexgorbatchev.com/SyntaxHighlighter/download/download.php?sh_current',
),
'path' => 'scripts',
'version arguments' => array(
'file' => 'scripts/shCore.js',
'pattern' => '@([0-9]+.[0-9]+.[0-9]+)@',
'lines' => 15,
'cols' => 30,
),
);
return $libraries;
}
Functions
Name![]() |
Description |
---|---|
syntaxhighlighter_filter_info | Implements hook_filter_info() |
syntaxhighlighter_form_comment_form_alter | Install custom comment validate function |
syntaxhighlighter_help | |
syntaxhighlighter_init | |
syntaxhighlighter_libraries_info | Implements hook_libraries_info(). |
syntaxhighlighter_menu | Menu for admin settings page |
syntaxhighlighter_modules_disabled | |
syntaxhighlighter_node_validate | Validate on the node input text to be sure there is no bad {syntaxhighlighter} tags |
syntaxhighlighter_permission | Implements hook_permission(). |
_syntaxhighlighter_comment_validate | Validate on comment input text to be sure there is no bad {syntaxhighlighter} tags |
_syntaxhighlighter_do_filter_prepare | Escape the content text in preparation for filtering: |
_syntaxhighlighter_do_filter_process | Revert back to <pre> tag |
_syntaxhighlighter_file_directory_path | This does the same thing as the old D6 file_directory_path() which is to give the default 'files' directory path relative the the web root |
_syntaxhighlighter_filter_tips | |
_syntaxhighlighter_format_has_syntaxhighlighter_filter | |
_syntaxhighlighter_get_enabled_language_brushes | |
_syntaxhighlighter_get_lib_location | |
_syntaxhighlighter_page_match | |
_syntaxhighlighter_scan_lib_location | Locate the syntaxhighlighter js library. The library must be placed in a directory named "syntaxhighlighter" in one of the following locations: 1) standard library paths provided by the "libraries" module (if installed) 2) the… |
_syntaxhighlighter_setup_autoloader_script | Create the autoload setup script file. Must call this whenever lib location and/or the enable brushes change. Make sure never call this if the js lib is not found |
_syntaxhighlighter_validate_input | Check for error with syntaxhighlighter input |
Constants
Name![]() |
Description |
---|---|
SYNTAXHIGHLGHTER_TAG_STRING | Use a completely none sense word for replacement when filtering so there is absolutely no chance this will conflict with something in content text |
SYNTAXHIGHLIGHTER_INJECT_EXCEPT_LISTED | Inject syntaxhighlighter on every page except the listed pages. |
SYNTAXHIGHLIGHTER_INJECT_IF_LISTED | Inject syntaxhighlighter on only the listed pages. |
SYNTAXHIGHLIGHTER_INJECT_PHP | Inject syntaxhighlighter if the associated PHP code returns TRUE. |
SYNTAXHIGHLIGHTER_PHP_PERMISSION |