CodeEditor ext: Add an experimental demo (off by default) mode to edit SyntaxHighlight_GeSHi sections inline using Ace editor

Not ready for prime-time. :) Doesn't actually save pages (just updates the live view), and seems to have problems when invoked multiple times.
Not all GeSHi languages are supported.

Colors of course are different.

Set $wgCodeEditorGeshiIntegration = true to enable; adds a 'section edit link' on source bits.
This commit is contained in:
Brion Vibber 2011-08-04 22:33:59 +00:00
parent 7f9abd7b7b
commit bf67581924
Notes: Brion Vibber 2011-08-04 22:33:59 +00:00
3 changed files with 194 additions and 0 deletions

View file

@ -8,4 +8,12 @@ class CodeEditorHooks {
}
return true;
}
public static function onBeforePageDisplay( $out, $skin ) {
global $wgCodeEditorGeshiIntegration;
if ( $wgCodeEditorGeshiIntegration ) {
$out->addModules( 'ext.codeEditor.geshi' );
}
return true;
}
}

View file

@ -23,6 +23,7 @@ $wgAutoloadClasses['CodeEditorHooks'] = $dir . '/CodeEditor.hooks.php';
$wgExtensionMessagesFiles['CodeEditor'] = $dir . '/CodeEditor.i18n.php';
$wgHooks['EditPage::showEditForm:initial'][] = 'CodeEditorHooks::editPageShowEditFormInitial';
$wgHooks['BeforePageDisplay'][] = 'CodeEditorHooks::onBeforePageDisplay';
$tpl = array(
'localBasePath' => dirname( __FILE__ ) . '/modules',
@ -51,9 +52,46 @@ $wgResourceModules['jquery.codeEditor'] = array(
// Minimal bundling of a couple bits of Ace
$wgResourceModules['ext.codeEditor.ace'] = array(
'group' => 'ext.codeEditor.ace',
'scripts' => array(
'ace/ace-uncompressed.js',
'ace/mode-javascript.js',
'ace/mode-css.js',
),
) + $tpl;
// Extra highlighting modes to match some availabel GeSHi highlighting languages
$wgResourceModules['ext.codeEditor.ace.modes'] = array(
'group' => 'ext.codeEditor.ace',
'scripts' => array(
'ace/mode-c_cpp.js',
'ace/mode-clojure.js',
'ace/mode-csharp.js',
'ace/mode-coffee.js',
'ace/mode-groovy.js',
'ace/mode-html.js',
'ace/mode-java.js',
'ace/mode-ocaml.js',
'ace/mode-perl.js',
'ace/mode-php.js',
'ace/mode-python.js',
'ace/mode-ruby.js',
'ace/mode-scala.js',
),
'dependencies' => 'ext.codeEditor.ace',
) + $tpl;
// Helper to add inline [edit] links to <source> sections
$wgResourceModules['ext.codeEditor.geshi'] = array(
'scripts' => array(
'ext.codeEditor.geshi.js'
),
'messages' => array(
'editsection',
'editsection-brackets',
'savearticle'
)
) + $tpl;
// Experimental feature; not ready yet.
$wgCodeEditorGeshiIntegration = false;

View file

@ -0,0 +1,148 @@
/**
* This is experimental and does not yet actually save anything back.
* Has to be manually enabled.
* Needs some code de-dup with the full-page JS/CSS page editing.
*/
$(function() {
var $sources = $('.mw-geshi');
if ($sources.length > 0) {
var setupEditor = function($div) {
var $link = $('<a>')
.text(mediaWiki.msg('editsection'))
.attr('href', '#')
.attr('title', 'Edit this code section')
.click(function(event) {
openEditor($div)
event.preventDefault();
});
var $edit = $('<span>')
.css('float', 'right')
.append('[')
.append($link)
.append(']'); // @fixme use the editsection-brackets msg
$div.prepend($edit);
};
var openEditor = function($div) {
var $main = $div.find('div'),
geshiLang = null,
matches = /(?:^| )source-([a-z0-9_-]+)/.exec($main.attr('class'));
if (matches) {
geshiLang = matches[1];
}
mediaWiki.loader.using('ext.codeEditor.ace.modes', function() {
// @fixme de-duplicate
var map = {
c: 'c_cpp',
cpp: 'c_cpp',
clojure: 'clojure',
csharp: 'csharp',
css: 'css',
coffeescript: 'coffee',
groovy: 'groovy',
html4strict: 'html',
html5: 'html',
java: 'java',
java5: 'java',
javascript: 'javascript',
jquery: 'javascript',
ocaml: 'ocaml',
perl: 'perl',
php: 'php',
python: 'python',
ruby: 'ruby',
scala: 'scala',
xml: 'xml'
};
// Disable some annoying commands
var canon = require('pilot/canon');
canon.removeCommand('replace'); // ctrl+R
canon.removeCommand('transposeletters'); // ctrl+T
canon.removeCommand('gotoline'); // ctrl+L
var $container = $('<div>')
.attr('style', 'top: 32px; left: 0px; right: 0px; bottom: 0px; border: 1px solid gray')
.text($main.text()); // quick hack :D
var $label = $('<label>').text('Source language: ');
var $langDropDown = $('<select>');
$.each(map, function(geshiLang, aceLang) {
var $opt = $('<option>')
.text(geshiLang)
.val(geshiLang)
.appendTo($langDropDown);
});
$langDropDown
.val(geshiLang)
.appendTo($label)
.change(function(event) {
setLanguage($(this).val());
});
var $save = $('<button>')
.text(mediaWiki.msg('savearticle'))
.click(function(event) {
// horrible hack ;)
var src = codeEditor.getSession().getValue();
var tag = '<source lang="' + geshiLang + '">' + src + '</source>';
$.ajax(wgScriptPath + '/api' + wgScriptExtension, {
data: {
action: 'parse',
text: tag,
format: 'json'
},
type: 'POST',
success: function(data, xhr) {
var $html = $(data.parse.text['*']);
$div.replaceWith($html)
setupEditor($html);
closeEditor();
event.preventDefault();
}
});
});
var $cancel = $('<button>')
.text('Close').click(function(event) {
$xcontainer.remove();
$div.css('display', 'block');
event.preventDefault();
});
var $controls = $('<div>')
.append($label)
.append($save)
.append($cancel);
var $xcontainer = $('<div style="position: relative"></div>')
.append($controls)
.append($container);
$xcontainer.width($main.width())
.height($main.height() * 1.1 + 64 + 32);
$div.css('display', 'none');
$xcontainer.insertAfter($div);
var codeEditor = ace.edit($container[0]);
var setLanguage = function(lang) {
geshiLang = lang;
var aceLang = map[geshiLang];
codeEditor.getSession().setMode(new (require("ace/mode/" + aceLang).Mode));
};
setLanguage(geshiLang);
var closeEditor = function() {
$xcontainer.remove();
$div.css('display', 'block');
};
});
};
$sources.each(function(i, div) {
var $div = $(div);
setupEditor($div);
});
}
});