Additional CodeEditor buttons

- toggle invisible characters.
- search and replace (disabled)
- indent/outdent
- line wrapping
- go to line

Icons by Connor Shea

Bug: T61923
Change-Id: I9e434d1b23f8254bc654ebbd31b5e4b70bbf5fe1
This commit is contained in:
Derk-Jan Hartman 2013-12-30 16:57:47 +01:00 committed by Ori.livneh
parent a7de818fcd
commit aba51ef4f5
22 changed files with 201 additions and 186 deletions

View file

@ -56,11 +56,18 @@ $wgResourceModules['jquery.codeEditor'] = array(
'jquery.ui.resizable',
'mediawiki.api',
'user.options',
'mediawiki.cookie',
),
'messages' => array(
'codeeditor-next-annotation',
'codeeditor-toolbar-toggle',
'codeeditor-save-with-errors'
'codeeditor-save-with-errors',
'codeeditor-invisibleChars-toggle',
'codeeditor-lineWrapping-toggle',
'codeeditor-searchReplace-toggle',
'codeeditor-gotoline',
'codeeditor-indent',
'codeeditor-outdent',
)
) + $tpl;

View file

@ -8,5 +8,11 @@
"codeeditor-desc": "Syntax-highlighted editing for JavaScript and CSS pages using [http://ace.ajax.org/ Ace editor]",
"codeeditor-next-annotation": "Go to next annotation",
"codeeditor-toolbar-toggle": "Toggle code editor",
"codeeditor-save-with-errors": "The document contains errors. Are you sure you want to save?"
"codeeditor-save-with-errors": "The document contains errors. Are you sure you want to save?",
"codeeditor-invisibleChars-toggle": "Toggle invisible characters",
"codeeditor-lineWrapping-toggle": "Toggle line wrapping",
"codeeditor-searchReplace-toggle": "Toggle search and replace dialog",
"codeeditor-gotoline": "Go to line number...",
"codeeditor-indent": "Indent",
"codeeditor-outdent": "Outdent"
}

View file

@ -10,5 +10,11 @@
"codeeditor-desc": "{{desc|name=Code Editor|url=https://www.mediawiki.org/wiki/Extension:CodeEditor}}",
"codeeditor-next-annotation": "Used as a label for button to navigate to the next line in the editor that has an annotation",
"codeeditor-toolbar-toggle": "Used as label for toolbar button.",
"codeeditor-save-with-errors": "Used as message in a dialog before saving a document with errors."
"codeeditor-save-with-errors": "Used as message in a dialog before saving a document with errors.",
"codeeditor-invisibleChars-toggle": "Used as label for toolbar button to show/hide non visible characters",
"codeeditor-lineWrapping-toggle": "Used as label for toolbar button to enable/disable line wrapping",
"codeeditor-searchReplace-toggle" : "Used as label for toolbar button to show/hide the search and replace dialog",
"codeeditor-gotoline": "Used as a label for toolbar button to navigate to a line number in the editor",
"codeeditor-indent": "Used as a label for toolbar button to indent text in the editor",
"codeeditor-outdent": "Used as a label for toolbar button to outdent text in the editor"
}

BIN
images/clear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 B

View file

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="22"
height="22"
id="svg2985"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="comment.svg"
inkscape:export-filename="/var/www/trunk/extensions/CodeEditor/images/code-selected.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs2987" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.197802"
inkscape:cx="-0.29784131"
inkscape:cy="19.57213"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1056"
inkscape:window-x="1920"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata2990">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-10)">
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="3.393523"
y="26.73111"
id="text2993"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="3.393523"
y="26.73111"
id="tspan2997"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Sans;-inkscape-font-specification:Sans Bold;fill:#000000">/*</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -1,80 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="22"
height="22"
id="svg2985"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="comment.svg"
inkscape:export-filename="/var/www/trunk/extensions/CodeEditor/images/code-selected.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs2987" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.197802"
inkscape:cx="-0.29784131"
inkscape:cy="19.57213"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1056"
inkscape:window-x="1920"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata2990">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-10)">
<rect
style="opacity:0.50000000000000000;fill:#ffffff;fill-opacity:1;stroke:#808080;stroke-opacity:1"
id="rect3188"
width="21"
height="21"
x="0.53581941"
y="10.567223"
rx="3" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#2a7fff;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
x="3.393523"
y="26.73111"
id="text2993"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="3.393523"
y="26.73111"
id="tspan2997"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Sans;-inkscape-font-specification:Sans Bold">/*</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

BIN
images/editor-off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
images/editor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
images/gotoline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
images/help.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
images/indent.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
images/markup-off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
images/markup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
images/outdent.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
images/search-replace.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
images/shortcuts.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
images/wrapping-off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
images/wrapping.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -1,4 +1,5 @@
.group-codeeditor-tools,
.group-codeeditor-format,
.group-codeeditor-style,
.codeEditor-ui-toolbar .group-insert,
.codeEditor-ui-toolbar .group-format,
.codeEditor-ui-toolbar .tabs span.tab-advanced,
@ -8,7 +9,8 @@
display: none;
}
.codeEditor-ui-toolbar .group-codeeditor-tools {
.codeEditor-ui-toolbar .group-codeeditor-format,
.codeEditor-ui-toolbar .group-codeeditor-style {
display: block;
}

View file

@ -1,5 +1,5 @@
/* Ace syntax-highlighting code editor extension for wikiEditor */
/*global require, ace, confirm */
/*global require, ace, confirm, prompt */
( function ( $, mw ) {
$.wikiEditor.modules.codeEditor = {
/**
@ -47,7 +47,16 @@
var saveAndExtend,
textSelectionFn,
hasErrorsOnSave = false,
returnFalse = function () { return false; };
cookieEnabled,
returnFalse = function () { return false; },
extIconPath = mw.config.get( 'wgCodeEditorAssetsPath', mw.config.get( 'wgExtensionAssetsPath' ) ) + '/CodeEditor/images/';
// Initialize state
cookieEnabled = parseInt( mw.cookie.get( 'codeEditor-' + context.instance + '-showInvisibleChars' ), 10 );
context.showInvisibleChars = ( cookieEnabled === 1 );
cookieEnabled = parseInt( mw.cookie.get( 'codeEditor-' + context.instance + '-lineWrappingActive' ), 10 );
context.lineWrappingActive = ( cookieEnabled === 1 );
context.showSearchReplace = 0;
/*
* Event Handlers
@ -95,29 +104,50 @@
*/
context.fn = $.extend( context.fn, {
'codeEditorToolbarIcon': function () {
// When loaded as a gadget, one may need to override the wiki's own assets path.
var iconPath = mw.config.get( 'wgCodeEditorAssetsPath', mw.config.get( 'wgExtensionAssetsPath' ) ) + '/CodeEditor/images/';
return iconPath + ( context.codeEditorActive ? 'code-selected.png' : 'code.png' );
return extIconPath + ( context.codeEditorActive ? 'editor.png' : 'editor-off.png' );
},
'invisibleCharsToolbarIcon': function () {
return extIconPath + ( context.showInvisibleChars ? 'markup.png' : 'markup-off.png' );
},
'lineWrappingToolbarIcon': function () {
return extIconPath + ( context.lineWrappingActive ? 'wrapping.png' : 'wrapping-off.png' );
},
'changeCookieValue': function ( cookieName, value ) {
mw.cookie.set(
'codeEditor-' + context.instance + '-' + cookieName,
value
);
},
'aceGotoLineColumn': function () {
var lineinput = prompt( 'Enter line number:', 'line:column' ),
matches = lineinput.split( ':' ),
line = 0,
column = 0;
if ( matches.length > 0 ) {
line = parseInt( matches[0], 10 ) || 0;
line--;
}
if ( matches.length > 1 ) {
column = parseInt( matches[1], 10 ) || 0;
column--;
}
context.codeEditor.navigateTo( line, column );
// Scroll up a bit to give some context
context.codeEditor.scrollToRow( line - 4 );
},
'setupCodeEditorToolbar': function () {
// Drop out some formatting that isn't relevant on these pages...
/*
context.api.removeFromToolbar( context, {
'section': 'main',
'group': 'format',
'tool': 'bold'
} );
context.api.removeFromToolbar( context, {
'section': 'main',
'group': 'format',
'tool': 'italic'
} );
*/
var callback = function ( context ) {
var toggleEditor,
toggleInvisibleChars,
toggleSearchReplace,
toggleLineWrapping,
indent, outdent, gotoLine;
toggleEditor = function ( context ) {
context.codeEditorActive = !context.codeEditorActive;
context.fn.setCodeEditorPreference( context.codeEditorActive );
context.fn.toggleCodeEditorToolbar();
context.fn.updateCodeEditorToolbarButton();
if ( context.codeEditorActive ) {
// set it back up!
@ -126,6 +156,44 @@
context.fn.disableCodeEditor();
}
};
toggleInvisibleChars = function ( context ) {
context.showInvisibleChars = !context.showInvisibleChars;
context.fn.changeCookieValue( 'showInvisibleChars', context.showInvisibleChars ? 1 : 0 );
context.fn.updateInvisibleCharsButton();
context.codeEditor.setShowInvisibles( context.showInvisibleChars );
};
toggleSearchReplace = function ( context ) {
context.showSearchReplace = !context.showSearchReplace;
if ( context.showSearchReplace ) {
ace.config.loadModule( 'ace/ext/searchbox', function ( e ) {
// ace.editor.searchBox.show();
e.Search( context.codeEditor, !0 );
} );
} else {
context.codeEditor.searchBox.hide();
}
};
toggleLineWrapping = function ( context ) {
context.lineWrappingActive = !context.lineWrappingActive;
context.fn.changeCookieValue( 'lineWrappingActive', context.lineWrappingActive ? 1 : 0 );
context.fn.updateLineWrappingButton();
context.codeEditor.getSession().setUseWrapMode( context.lineWrappingActive );
};
indent = function ( context ) {
context.codeEditor.execCommand( 'indent' );
};
outdent = function ( context ) {
context.codeEditor.execCommand( 'outdent' );
};
gotoLine = function ( context ) {
context.codeEditor.execCommand( 'gotolinecolumn' );
};
context.api.addToToolbar( context, {
'section': 'main',
'groups': {
@ -137,26 +205,95 @@
'icon': context.fn.codeEditorToolbarIcon(),
'action': {
'type': 'callback',
'execute': callback
'execute': toggleEditor
}
}
}
},
'codeeditor-tools': {
/* TODO: This wasn't working for brion for some reason
'codeeditor-format': {
'tools': {
'indent': {
'labelMsg': 'codeeditor-indent',
'type': 'button',
'icon': extIconPath + 'indent.png',
'action': {
'type': 'callback',
'execute': indent
}
},
'outdent': {
'labelMsg': 'codeeditor-outdent',
'type': 'button',
'icon': extIconPath + 'outdent.png',
'action': {
'type': 'callback',
'execute': outdent
}
}
}
},
*/
'codeeditor-style': {
'tools': {
'invisibleChars': {
'labelMsg': 'codeeditor-invisibleChars-toggle',
'type': 'button',
'icon': context.fn.invisibleCharsToolbarIcon(),
'action': {
'type': 'callback',
'execute': toggleInvisibleChars
}
},
'lineWrapping': {
'labelMsg': 'codeeditor-lineWrapping-toggle',
'type': 'button',
'icon': context.fn.lineWrappingToolbarIcon(),
'action': {
'type': 'callback',
'execute': toggleLineWrapping
}
},
'gotoLine': {
'labelMsg': 'codeeditor-gotoline',
'type': 'button',
'icon': extIconPath + 'gotoline.png',
'action': {
'type': 'callback',
'execute': gotoLine
}
},
'toggleSearchReplace': {
'labelMsg': 'codeeditor-searchReplace-toggle',
'type': 'button',
'icon': extIconPath + 'search-replace.png',
'action': {
'type': 'callback',
'execute': toggleSearchReplace
}
}
}
}
}
} );
$( '.group-codeeditor-tools' ).prependTo( '.section-main' );
$( '.group-codeeditor-style' ).prependTo( '.section-main' );
$( '.group-codeeditor-format' ).prependTo( '.section-main' );
$( '.group-codeeditor-main' ).prependTo( '.section-main' );
},
'toggleCodeEditorToolbar': function () {
var target, $img;
target = 'img.tool[rel=codeEditor]';
$img = context.modules.toolbar.$toolbar.find( target );
$img.attr( 'src', context.fn.codeEditorToolbarIcon() );
'updateButtonIcon': function ( targetName, iconFn ) {
var target = 'img.tool[rel=' + targetName + ']',
$img = context.modules.toolbar.$toolbar.find( target );
$img.attr( 'src', iconFn() );
},
'updateCodeEditorToolbarButton': function () {
context.fn.updateButtonIcon( 'codeEditor', context.fn.codeEditorToolbarIcon );
},
'updateInvisibleCharsButton': function () {
context.fn.updateButtonIcon( 'invisibleChars', context.fn.invisibleCharsToolbarIcon );
},
'updateLineWrappingButton': function () {
context.fn.updateButtonIcon( 'lineWrapping', context.fn.lineWrappingToolbarIcon );
},
'setCodeEditorPreference': function ( prefValue ) {
var api = new mw.Api();
@ -210,6 +347,7 @@
context.codeEditor.commands.removeCommand( 'gotoline' ); // ctrl+L
context.codeEditor.setReadOnly( box.prop( 'readonly' ) );
context.codeEditor.setShowInvisibles( context.showInvisibleChars );
// The options to enable
context.codeEditor.setOptions( {
@ -217,13 +355,21 @@
enableSnippets: true
} );
context.codeEditor.commands.addCommand( {
name: 'gotolinecolumn',
bindKey: { mac: 'Command-Shift-L', windows: 'Ctrl-Alt-L' },
exec: context.fn.aceGotoLineColumn
} );
box.closest( 'form' )
.submit( context.evt.codeEditorSubmit )
.find( '#wpSave' ).click( context.evt.codeEditorSave );
session = context.codeEditor.getSession();
// Use proper tabs
session.setUseSoftTabs( false );
session.setUseWrapMode( context.lineWrappingActive );
if ( mw.hook ) {
mw.hook( 'codeEditor.configure' ).fire( session );