diff --git a/editors/codemirror.inc b/editors/codemirror.inc new file mode 100644 index 0000000..c25efca --- /dev/null +++ b/editors/codemirror.inc @@ -0,0 +1,157 @@ + 'CodeMirror', + 'vendor url' => 'http://codemirror.net', + 'download url' => 'http://codemirror.net', + 'library path' => wysiwyg_get_path('codemirror'), + 'libraries' => array( + '' => array( + 'title' => 'CodeMirror', + 'files' => array( + 'lib/codemirror.js', + ), + ), + ), + 'version callback' => 'wysiwyg_codemirror_version', + 'settings callback' => 'wysiwyg_codemirror_settings', + 'plugin callback' => 'wysiwyg_codemirror_plugins', + 'load callback' => 'wysiwyg_codemirror_load', + 'versions' => array( + '2' => array( + 'js files' => array('codemirror.js'), + 'css files' => array('codemirror-2.css'), + ), + ), + ); + return $editor; +} + +/** + * Detect editor version. + * + * @param $editor + * An array containing editor properties as returned from hook_editor(). + * + * @return + * The installed editor version. + */ +function wysiwyg_codemirror_version($editor) { + $fp = $editor['library path'] . '/lib/codemirror.js'; + if (!file_exists($fp)) { + return; + } + $fp = fopen($fp, 'r'); + $line = fgets($fp); + if (preg_match('@([0-9\.]+)$@', $line, $version)) { + fclose($fp); + return $version[1]; + } + fclose($fp); +} + +/** + * Perform additional actions upon loading this editor. + * + * @param $editor + * A processed hook_editor() array of editor properties. + * @param $library + * The internal library name (array key) to use. + */ +function wysiwyg_codemirror_load($editor, $library) { + // @TODO: Make themes and modes into editor settings + drupal_add_css($editor['library path'] . '/lib/codemirror.css'); + drupal_add_css($editor['library path'] . '/theme/default.css'); + + drupal_add_js($editor['library path'] . '/lib/codemirror.js'); + drupal_add_js($editor['library path'] . '/mode/clike/clike.js'); + drupal_add_js($editor['library path'] . '/mode/css/css.js'); + drupal_add_js($editor['library path'] . '/mode/diff/diff.js'); + drupal_add_js($editor['library path'] . '/mode/haskell/haskell.js'); + drupal_add_js($editor['library path'] . '/mode/htmlmixed/htmlmixed.js'); + drupal_add_js($editor['library path'] . '/mode/javascript/javascript.js'); + drupal_add_js($editor['library path'] . '/mode/php/php.js'); + drupal_add_js($editor['library path'] . '/mode/stex/stex.js'); + drupal_add_js($editor['library path'] . '/mode/xml/xml.js'); + + drupal_add_css($editor['library path'] . '/lib/util/simple-hint.css'); + drupal_add_js($editor['library path'] . '/lib/util/simple-hint.js'); + drupal_add_js($editor['library path'] . '/lib/util/xml-hint.js'); + drupal_add_js($editor['library path'] . '/lib/util/closetag.js'); +} + +/** + * Return runtime editor settings for a given wysiwyg profile. + * + * @param $editor + * A processed hook_editor() array of editor properties. + * @param $config + * An array containing wysiwyg editor profile settings. + * @param $theme + * The name of a theme/GUI/skin to use. + * + * @return + * A settings array to be populated in + * Drupal.settings.wysiwyg.configs.{editor} + */ +function wysiwyg_codemirror_settings($editor, $config, $theme) { + /* Defaults */ + $settings = array( + 'mode' => 'text/html', + 'indentUnit' => 2, + 'indentWithTabs' => FALSE, + 'smartIndent' => FALSE, + 'tabMode' => 'shift', + 'enterMode' => 'indent', + 'electricChars' => FALSE, + 'lineNumbers' => FALSE, + 'gutter' => FALSE, + 'readOnly' => FALSE, + 'matchBrackets' => FALSE, + 'autoComplete' => FALSE, + ); + + $all_settings = array_keys($settings); + + if (is_array($config['buttons']['default'])) { + foreach ($config['buttons']['default'] as $key => $value) { + if ($value) { + if (in_array($key, $all_settings)) { + $settings[$key] = ($value != 0); + } + } + } + } + + return $settings; +} + +/** + * Return internal plugins for this editor; semi-implementation of hook_wysiwyg_plugin(). + */ +function wysiwyg_codemirror_plugins($editor) { + return array( + 'default' => array( + 'buttons' => array( + 'autoComplete' => t('Autocomplete'), + 'lineNumbers' => t('Line Numbers'), + 'matchBrackets' => t('Match Brackets'), + 'electricChars' => t('Electric Characters'), + 'smartIndent' => t('Smart Indent'), + 'indentWithTabs' => t('Indent With Tabs'), + 'gutter' => t('Gutter'), + 'matchBrackets' => t('Match Brackets') + ) + ), + 'internal' => TRUE, + ); +} diff --git a/editors/css/codemirror-2.css b/editors/css/codemirror-2.css new file mode 100644 index 0000000..6dae03e --- /dev/null +++ b/editors/css/codemirror-2.css @@ -0,0 +1,7 @@ + +/** + * CodeMirror + */ +.CodeMirror { + border: 1px solid #ddd +} diff --git a/editors/js/codemirror.js b/editors/js/codemirror.js new file mode 100644 index 0000000..67516b3 --- /dev/null +++ b/editors/js/codemirror.js @@ -0,0 +1,52 @@ +(function($) { + +/* Maintain a list of active editors on the page */ +var instances = new Object; + +/** + * Attach this editor to a target element. + * + * See Drupal.wysiwyg.editor.attach.none() for a full desciption of this hook. + */ +Drupal.wysiwyg.editor.attach.codemirror = function(context, params, settings) { + if (settings.autoComplete) { + var pairedTags = ("a abbr acronym address applet b bdo big blockquote body button" + + " caption center cite code colgroup del dfn dir div dl em fieldset font form" + + " frameset h1 h2 h3 h4 h5 h6 head html i iframe ins kbd label legend li map" + + " menu noframes noscript object ol optgroup option p pre q s samp script select small" + + " span strike strong style sub sup table tbody td textarea tfoot th thead title tr tt u ul var").split(" "); + CodeMirror.xmlHints['<'] = pairedTags; + CodeMirror.xmlHints['/'] = pairedTags; + settings.extraKeys = { + "'<'": function(cm) { CodeMirror.xmlHint(cm, '<'); }, + "'>'": function(cm) { cm.closeTag(cm, '>'); }, + "'/'": function(cm) { cm.closeTag(cm, '/'); }, + "Ctrl-Space": function(cm) { CodeMirror.xmlHint(cm, ''); }, + } + } + var textArea = document.getElementById(params.field); + if (textArea) { + instances[params.field] = CodeMirror.fromTextArea(textArea, settings); + } + + if (params.resizable) { + jQuery('.CodeMirror-scroll').css({ + // @TODO: Get these from editor settings + //'height' : 'auto', + 'overflow-y' : 'hidden', + 'overflow-x' : 'auto' + }); + } +}; + +/** + * Detach a single or all editors. + * + * See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook. + */ +Drupal.wysiwyg.editor.detach.codemirror = function(context, params) { + instances[params.field].toTextArea(); + delete instances[params.field]; +}; + +})(jQuery);