ace_editor.module in Ace Code Editor 7
Same filename and directory in other branches
Ace Editor module.
File
ace_editor.moduleView source
<?php
/**
* @file
* Ace Editor module.
*/
/**
* Implements hook_menu().
*
* Add a settings page to configure the module.
*/
function ace_editor_menu() {
$items = array();
$items['admin/config/content/ace-editor'] = array(
'title' => 'Ace Editor',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ace_editor_settings_form',
),
'access arguments' => array(
'configure ace editor',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'ace_editor.admin.inc',
);
return $items;
}
/**
* Implements hook_permission().
*/
function ace_editor_permission() {
return array(
'configure ace editor' => array(
'title' => t('Configure Ace Editor'),
'description' => t('Access the configuration page for Ace Editor.'),
'restrict access' => TRUE,
),
);
}
/**
* An API function to embed read-only editors into template files.
*/
function ace_editor_add($content, $user_settings) {
// Get the default settings and override them with settings defined by user.
$settings = ace_editor_field_formatter_default_settings();
foreach ($user_settings as $key => $value) {
$settings[$key] = $value;
}
$settings = ace_editor_make_js_friendly_settings($settings);
// Get a unique index for the next pre-element added by this API function.
$pre_id = drupal_html_id('ace-editor-add');
$pre = '<pre id="' . $pre_id . '">' . $content . '</pre>';
// Put all instances and their settings to JS.
$js_ettings = array();
$js_settings['ace_editor']['editor_instances'][] = array(
'id' => $pre_id,
'content' => $content,
'settings' => $settings,
);
// Add the javascript files needed.
ace_editor_add_js($settings, FALSE);
drupal_add_js($js_settings, 'setting');
drupal_add_js(drupal_get_path('module', 'ace_editor') . '/js/ace_editor.js');
drupal_add_css(drupal_get_path('module', 'ace_editor') . '/styles/ace_editor.css');
return $pre;
}
/**
* Implements hook_form_alter().
*
* For selected forms where Ace will be used, add the JS nessesary
*/
function ace_editor_form_alter(&$form, &$form_state, $form_id) {
// Node edit forms.
if (isset($form['#node_edit_form']) && $form['#node_edit_form']) {
$form_ident = 'node_' . $form['nid']['#value'];
}
elseif (isset($form['module']) && $form['module']['#value'] == 'block') {
$form_ident = 'block_' . $form['delta']['#value'];
}
elseif ($form_id == 'ctools_custom_content_type_edit_form') {
$form_ident = $form_id;
}
elseif ($form_id == 'fieldable_panels_panes_fieldable_panels_pane_content_type_edit_form') {
$form_ident = $form_id;
}
elseif (isset($form['#entity_type']) && $form['#entity_type'] == 'bean') {
$form_ident = $form_id;
}
elseif ($form_id == 'devel_execute_form' || $form_id == 'devel_execute_block_form') {
$form_ident = $form_id;
$form['execute']['code']['#attributes']['class'][] = 'ace-enabled';
$form['execute']['code']['#resizable'] = FALSE;
$form['#submit'] = array(
'ace_editor_execute_form_submit',
);
// Ace editor requires initial PHP tag so prepend it.
if (strpos($form['execute']['code']['#default_value'], '<?php') !== 0) {
$form['execute']['code']['#default_value'] = '<?php' . $form['execute']['code']['#default_value'];
}
$form['execute']['code']['#description'] = t('Enter some code. Use <code><?php ?></code> tags to benefit from the Ace Editor.');
// Restore the textarea content.
$_SESSION['devel_execute_code'] = $form['execute']['code']['#default_value'];
}
elseif ($form_id == 'views_ui_config_item_form' && strpos($form['#title'], 'Global: Text area') !== FALSE) {
$form_ident = $form_id;
}
elseif ($form_id == 'i18n_string_translate_page_form') {
$form_ident = $form_id;
}
elseif ($form_id == 'webform_configure_form') {
$form_ident = $form_id;
}
elseif ($form_id == 'taxonomy_form_term') {
$form_ident = $form_id;
}
else {
return;
}
// Add JavaScript to the form if the ace editor library is installed.
if (ace_editor_library_installed()) {
$form['ace_editor_identifier'] = array(
'#type' => 'hidden',
'#value' => $form_ident,
);
$form['#after_build'] = array(
'ace_editor_node_block_edit_form_attach_js',
);
}
else {
global $base_path;
drupal_set_message(t('The Ace Editor JS library is missing, please check the !readme_link for installation instructions.', array(
'!readme_link' => '<a href="' . $base_path . drupal_get_path('module', 'ace_editor') . '/README.txt" target="_blank">README</a>',
)), 'error');
}
}
/**
* Add JS to the page containing the affected forms.
*/
function ace_editor_node_block_edit_form_attach_js($form) {
global $base_path;
$add_js_settings = array(
'ace_src_dir' => $base_path . libraries_get_path('ace') . '/src/',
'autocomplete' => variable_get('ace_editor_autocomplete', TRUE),
'autowrap' => variable_get('ace_editor_autowrap', TRUE),
'available_modes' => ace_editor_get_modes(),
'fontsize' => variable_get('ace_editor_fontsize', '12pt'),
'invisibles' => variable_get('ace_editor_invisibles', FALSE),
'linehighlighting' => variable_get('ace_editor_linehighlighting', TRUE),
'line_numbers' => variable_get('ace_editor_line_numbers', TRUE),
'printmargin' => variable_get('ace_editor_printmargin', FALSE),
'codefolding' => variable_get('ace_editor_codefolding', 'markbegin'),
'syntax' => variable_get('ace_editor_default_syntax', 'html'),
'tabsize' => variable_get('ace_editor_tabsize', 2),
'text_formats' => array_values(variable_get('ace_editor_filter_formats', array())),
'theme' => variable_get('ace_editor_theme', 'cobalt'),
);
$js_settings = array(
'ace_editor' => array(
'admin' => $add_js_settings,
),
);
ace_editor_add_js($add_js_settings, TRUE);
drupal_add_js($js_settings, 'setting');
drupal_add_js(drupal_get_path('module', 'ace_editor') . '/js/ace_editor.admin.js');
drupal_add_js(libraries_get_path('ace') . '/src/mode-html.js');
drupal_add_css(drupal_get_path('module', 'ace_editor') . '/styles/ace_editor.admin.css');
return $form;
}
/**
* Implements hook_field_formatter_info().
*/
function ace_editor_field_formatter_info() {
return array(
'ace_editor_code_readonly_formatter' => array(
'label' => t('Code syntax highlighting'),
'field types' => array(
'text_long',
'text_with_summary',
),
'settings' => ace_editor_field_formatter_default_settings(),
),
);
}
/**
* Implements hook_field_formatter_settings_form().
*/
function ace_editor_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
// Get the settings.
$settings = $instance['display'][$view_mode]['settings'];
$element = get_setting_form_elements($settings);
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function ace_editor_field_formatter_settings_summary($field, $instance, $view_mode) {
// Get the settings.
$settings = $instance['display'][$view_mode]['settings'];
$themes_dict = ace_editor_get_themes();
$modes_dict = ace_editor_get_modes();
$summary = t('Show content with code syntax highlighting for @syntax in the @theme theme.', array(
'@syntax' => $modes_dict[$settings['syntax']],
'@theme' => $themes_dict[$settings['theme']],
));
return $summary;
}
/**
* Implements hook_field_formatter_view().
*/
function ace_editor_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
// Get the settings.
$settings = ace_editor_make_js_friendly_settings($display['settings']);
$element = array();
$js_settings = array(
'ace_editor' => array(
'editor_instances' => array(),
),
);
// Add all values to their own editor intance.
foreach ($items as $delta => $item) {
$element_id = $field['field_name'] . '-' . $delta . '-pre';
$pre_element = '<pre id="' . $element_id . '" </pre>';
$element[]['#markup'] = $pre_element;
$js_settings['ace_editor']['editor_instances'][] = array(
'id' => $element_id,
'content' => $item['value'],
'settings' => $settings,
);
}
ace_editor_add_js($settings, FALSE);
drupal_add_js($js_settings, 'setting');
drupal_add_js(drupal_get_path('module', 'ace_editor') . '/js/ace_editor.js');
drupal_add_css(drupal_get_path('module', 'ace_editor') . '/styles/ace_editor.css');
return $element;
}
/**
* Implements hook_filter_info().
*/
function ace_editor_filter_info() {
$filters['ace_editor'] = array(
'title' => t('Syntax highlighting'),
'description' => t('Use <ace> and </ace> tags to show it with syntax highlighting.
Add attributes to <ace> tag to control formatting. <b>CAUTION:</b> This prevents content that use this filter from being cached. It is recomended not to be selected on site wide-used text formats like HTML Full/Filtered, which may have an impact on the site\'s overall performance. Enable it on a custom text format that will be only used for the content to be syntax-highlighted.'),
'process callback' => 'ace_editor_filter_process',
'settings callback' => 'ace_editor_filter_settings',
'default settings' => ace_editor_field_formatter_default_settings(),
'cache' => FALSE,
);
return $filters;
}
/**
* Returns the settings form for the text filter.
*/
function ace_editor_filter_settings($form, &$form_state, $filter, $format, $defaults, $filters) {
$settings = $filter->settings;
if (empty($settings)) {
$settings = $defaults;
}
$element = get_setting_form_elements($settings);
array_unshift($element, array(
'#markup' => t('<p>This is the default settings, these settings can be overridden by adding attributes<?php ?> to the tag.</p>'),
));
return $element;
}
/**
* Implements hook_filter_FILTER_prepare().
*/
function ace_editor_filter_process($text, $filter, $format, $langcode, $cache, $cache_id) {
if (preg_match_all("/<ace.*?>(.*?)\\s*<\\/ace>/s", $text, $match)) {
$js_settings = array(
'ace_editor' => array(
'editor_instances' => array(),
),
);
$add_js_settings = array();
foreach ($match[0] as $key => $value) {
$element_id = 'ace-editor-inline' . $key;
$content = trim($match[1][$key], "\n\r\0\v");
$replace = '<pre id="' . $element_id . '"></pre>';
// Override settings with attributes on the tag.
$settings = $filter->settings;
$tag_attributes = tag_attributes('ace', $value);
if ($tag_attributes) {
foreach ($tag_attributes as $attribute_key => $attribute_value) {
$settings[$attribute_key] = $attribute_value;
}
}
$settings = ace_editor_make_js_friendly_settings($settings);
$add_js_settings[] = $settings;
$js_settings['ace_editor']['editor_instances'][] = array(
'id' => $element_id,
'content' => $content,
'settings' => $settings,
);
$text = str_replace_once($value, $replace, $text);
}
drupal_add_js($js_settings, 'setting');
ace_editor_add_js($add_js_settings, FALSE);
drupal_add_js(drupal_get_path('module', 'ace_editor') . '/js/ace_editor.js');
drupal_add_css(drupal_get_path('module', 'ace_editor') . '/styles/ace_editor.css');
}
return $text;
}
/**
* Custom function to replace the code only once.
*
* Probably not the most efficient way, but at least it works.
*/
function str_replace_once($needle, $replace, $haystack) {
// Looks for the first occurence of $needle in $haystack
// and replaces it with $replace.
$pos = strpos($haystack, $needle);
if ($pos === FALSE) {
// Nothing found.
return $haystack;
}
return substr_replace($haystack, $replace, $pos, strlen($needle));
}
/**
* Get all attributes of an <ace> tag in key/value pairs.
*/
function tag_attributes($element_name, $xml) {
// Grab the string of attributes inside the editor tag.
$found = preg_match('#<' . $element_name . '\\s+([^>]+(?:"|\'))\\s?/?>#', $xml, $matches);
if ($found == 1) {
$attribute_array = array();
$attribute_string = $matches[1];
// Match attribute-name attribute-value pairs.
$found = preg_match_all('#([^\\s=]+)\\s*=\\s*(\'[^<\']*\'|"[^<"]*")#', $attribute_string, $matches, PREG_SET_ORDER);
if ($found != 0) {
// Create an associative array that matches attribute names
// with their values.
foreach ($matches as $attribute) {
$value = substr($attribute[2], 1, -1);
if ($value == "1" || $value == "0" || $value == "true" || $value == "false") {
$value = intval($value);
}
$attribute_array[$attribute[1]] = $value;
}
return $attribute_array;
}
}
// Attributes either weren't found, or couldn't be extracted
// by the regular expression.
return FALSE;
}
/**
* Field formatter settings form.
*/
function get_setting_form_elements($settings) {
return array(
'theme' => array(
'#type' => 'select',
'#title' => t('Theme'),
'#options' => ace_editor_get_themes(),
'#default_value' => $settings['theme'],
'#attributes' => array(
'style' => 'width: 150px;',
),
),
'syntax' => array(
'#type' => 'select',
'#title' => t('Syntax'),
'#description' => t('The syntax that will be highlighted.'),
'#options' => ace_editor_get_modes(),
'#default_value' => $settings['syntax'],
'#attributes' => array(
'style' => 'width: 150px;',
),
),
'height' => array(
'#type' => 'textfield',
'#title' => t('Height'),
'#description' => t('The height of the editor in either pixels or percents.
You can use "auto" to let the editor calculate the adequate height.'),
'#default_value' => $settings['height'],
'#attributes' => array(
'style' => 'width: 100px;',
),
),
'width' => array(
'#type' => 'textfield',
'#title' => t('Width'),
'#description' => t('The width of the editor in either pixels or percents.'),
'#default_value' => $settings['width'],
'#attributes' => array(
'style' => 'width: 100px;',
),
),
'font-size' => array(
'#type' => 'textfield',
'#title' => t('Font size'),
'#description' => t('The the font size of the editor.'),
'#default_value' => $settings['font-size'],
'#attributes' => array(
'style' => 'width: 100px;',
),
),
// Wrapmode breaks the read-only editor if activated.
// 'autowrap' => array(
// '#type' => 'checkbox',
// '#title' => t('Autowrap lines'),
// '#default_value' => $settings['autowrap'],
// ),
'linehighlighting' => array(
'#type' => 'checkbox',
'#title' => t('Line highlighting'),
'#default_value' => $settings['linehighlighting'],
),
'line-numbers' => array(
'#type' => 'checkbox',
'#title' => t('Show line numbers'),
'#default_value' => $settings['line-numbers'],
),
);
}
/**
* The default settings used with the Ace field formatter.
*/
function ace_editor_field_formatter_default_settings() {
return array(
'autocomplete' => FALSE,
'autowrap' => TRUE,
'font-size' => variable_get('ace_editor_fontsize', '12pt'),
'height' => '200px',
'invisibles' => FALSE,
'line-numbers' => FALSE,
'linehighlighting' => TRUE,
'print-margin' => FALSE,
'syntax' => variable_get('ace_editor_default_syntax', 'html'),
'tabsize' => variable_get('ace_editor_tabsize', 2),
'theme' => variable_get('ace_editor_theme', 'cobalt'),
'width' => '100%',
);
}
/**
* Add all JavaScript needed for the editor to work on the next page.
*/
function ace_editor_add_js($add_js_settings, $for_admin_pages) {
drupal_add_library('ace_editor', 'ace', FALSE);
global $base_path;
$ace_lib_path = libraries_get_path('ace');
if (isset($add_js_settings[0]) && is_array($add_js_settings[0])) {
foreach ($add_js_settings as $key => $settings) {
drupal_add_js($ace_lib_path . '/src/theme-' . $settings['theme'] . '.js', array(
'preprocess' => FALSE,
));
drupal_add_js($ace_lib_path . '/src/mode-' . $settings['syntax'] . '.js', array(
'preprocess' => FALSE,
));
}
}
else {
drupal_add_js($ace_lib_path . '/src/theme-' . $add_js_settings['theme'] . '.js', array(
'preprocess' => FALSE,
));
drupal_add_js($ace_lib_path . '/src/mode-' . $add_js_settings['syntax'] . '.js', array(
'preprocess' => FALSE,
));
}
if ($for_admin_pages) {
drupal_add_library('system', 'ui.resizable');
}
}
/**
* Replaces dashes with underscores in keys for use with JS.
*/
function ace_editor_make_js_friendly_settings($settings) {
$js_friendly = array();
foreach ($settings as $key => $value) {
$js_friendly[str_replace('-', '_', $key)] = $value;
}
return $js_friendly;
}
/**
* Returns the installed themes.
*/
function ace_editor_get_themes() {
// Available themes are loaded on installation.
$assets = variable_get('ace_editor_assets', array(
'theme' => array(
'cobalt' => 'Cobalt',
),
));
$themes = $assets['theme'];
asort($themes);
return $themes;
}
/**
* Returns all of the modes.
*/
function ace_editor_get_modes() {
// Available modeses are loaded on installation.
$assets = variable_get('ace_editor_assets', array(
'mode' => array(
'html' => 'HTML',
),
));
asort($assets['mode']);
$modes = array_merge($assets['mode'], array(
// Translate some most used languages to their common name.
'c_cpp' => 'C/C++',
'coffee' => 'CoffeeScript',
'csharp' => 'C#',
'css' => 'CSS',
'html' => 'HTML',
'json' => 'JSON',
'less' => 'LESS',
'php' => 'PHP',
'scss' => 'SCSS',
'xml' => 'XML',
'yaml' => 'YAML',
));
return $modes;
}
/**
* Implements hook_library().
*
* For using drupal_add_library()
*/
function ace_editor_library() {
$libraries['ace'] = array(
'title' => 'Ace Editor',
'website' => 'http://ace.c9.io/',
'version' => '',
'js' => array(
libraries_get_path('ace') . '/src/ace.js' => array(),
libraries_get_path('ace') . '/src/ext-language_tools.js' => array(),
),
);
return $libraries;
}
/**
* Implements hook_libraries_info().
*/
function ace_editor_libraries_info() {
$libraries['ace'] = array(
'title' => 'Ace Editor',
'vendor url' => 'http://ace.c9.io/',
'download url' => 'https://github.com/ajaxorg/ace-builds/archive/master.zip',
'version arguments' => array(
'file' => 'package.json',
'pattern' => '/"version": "(\\d+\\.+\\d+.+\\d+)"/',
),
'files' => array(
'js' => array(
'src/ace.js',
// Required for autocompletion.
'src/ext-language_tools.js',
),
),
);
return $libraries;
}
/**
* Returns if the library is installed.
*/
function ace_editor_library_installed() {
$library = libraries_detect('ace');
return isset($library['installed']) && $library['installed'];
}
/**
* Fills the global var 'ace_editor_assets'.
*/
function ace_editor_get_assets() {
// Find out available themes and modes in the library.
$libraries = libraries_get_libraries();
if (isset($libraries['ace'])) {
$files = file_scan_directory($libraries['ace'] . '/src', '/(mode|theme)-(.+)\\.js$/', array(
'recurse' => FALSE,
));
$assets = array();
foreach ($files as $file_info) {
$asset = explode('-', $file_info->name);
$assets[$asset[0]][$asset[1]] = ucwords(str_replace('_', ' ', $asset[1]));
}
if (!empty($assets)) {
variable_set('ace_editor_assets', $assets);
}
}
}
/**
* Implements hook_init().
*/
function ace_editor_init() {
// Load the library assets if it was not installed before enabling the module.
if (!variable_get('ace_editor_assets') && ace_editor_library_installed()) {
ace_editor_get_assets();
}
// Load PHP consoles support for specific modules.
if (module_exists('devel')) {
$module_path = drupal_get_path('module', 'ace_editor');
// Load module includes.
module_load_include('inc', 'ace_editor', 'ace_editor.devel');
}
}
Functions
Name | Description |
---|---|
ace_editor_add | An API function to embed read-only editors into template files. |
ace_editor_add_js | Add all JavaScript needed for the editor to work on the next page. |
ace_editor_field_formatter_default_settings | The default settings used with the Ace field formatter. |
ace_editor_field_formatter_info | Implements hook_field_formatter_info(). |
ace_editor_field_formatter_settings_form | Implements hook_field_formatter_settings_form(). |
ace_editor_field_formatter_settings_summary | Implements hook_field_formatter_settings_summary(). |
ace_editor_field_formatter_view | Implements hook_field_formatter_view(). |
ace_editor_filter_info | Implements hook_filter_info(). |
ace_editor_filter_process | Implements hook_filter_FILTER_prepare(). |
ace_editor_filter_settings | Returns the settings form for the text filter. |
ace_editor_form_alter | Implements hook_form_alter(). |
ace_editor_get_assets | Fills the global var 'ace_editor_assets'. |
ace_editor_get_modes | Returns all of the modes. |
ace_editor_get_themes | Returns the installed themes. |
ace_editor_init | Implements hook_init(). |
ace_editor_libraries_info | Implements hook_libraries_info(). |
ace_editor_library | Implements hook_library(). |
ace_editor_library_installed | Returns if the library is installed. |
ace_editor_make_js_friendly_settings | Replaces dashes with underscores in keys for use with JS. |
ace_editor_menu | Implements hook_menu(). |
ace_editor_node_block_edit_form_attach_js | Add JS to the page containing the affected forms. |
ace_editor_permission | Implements hook_permission(). |
get_setting_form_elements | Field formatter settings form. |
str_replace_once | Custom function to replace the code only once. |
tag_attributes | Get all attributes of an <ace> tag in key/value pairs. |