TheDJ has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/122601

Change subject: Add a status bar to the CodeEditor
......................................................................

Add a status bar to the CodeEditor

- Show counts of errors/warnings/info annotations. This is useful
  because the annotations are in the gutter, so in big files it takes
  a lot of scrolling to look for errors
- Clicking the totals count skips you to the 'next' annotation
- If the current line contains an error, show the message of the error
  in the status bar.
- Show the current line:column number, the selection range and the
  editor mode.
- Degrades to a useful and readable but not pretty state in IE7

More complex version of: Ib9f08fcbc0365302756095b9027289736856fc73
Bug: 63294

Change-Id: Ided0804d5eb7864452287087dd1cf5a3dd8ff078
---
M CodeEditor.php
A modules/jquery.codeEditor.css
M modules/jquery.codeEditor.js
3 files changed, 214 insertions(+), 2 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/CodeEditor 
refs/changes/01/122601/1

diff --git a/CodeEditor.php b/CodeEditor.php
index f261776..cd25758 100644
--- a/CodeEditor.php
+++ b/CodeEditor.php
@@ -14,7 +14,7 @@
        'path' => __FILE__,
        'name' => 'CodeEditor',
        'url' => 'https://www.mediawiki.org/wiki/Extension:CodeEditor',
-       'author' => array( 'Brion Vibber', 'authors of Ace (ajax.org)' ),
+       'author' => array( 'Brion Vibber', 'Derk-Jan Hartman', 'authors of Ace 
(ajax.org)' ),
        'descriptionmsg' => 'codeeditor-desc',
 );
 
@@ -43,6 +43,7 @@
 
 $wgResourceModules['jquery.codeEditor'] = array(
        'scripts' => 'jquery.codeEditor.js',
+       'styles' => 'jquery.codeEditor.css',
        'dependencies' => array(
                'jquery.wikiEditor',
                'ext.codeEditor.ace',
diff --git a/modules/jquery.codeEditor.css b/modules/jquery.codeEditor.css
new file mode 100644
index 0000000..00eab13
--- /dev/null
+++ b/modules/jquery.codeEditor.css
@@ -0,0 +1,38 @@
+.codeEditor-status {
+       clear: both;
+       width: 100%;
+       background-color: #F0F0F0;
+       border-top: 1px solid silver;
+       display: table;
+}
+
+.codeEditor-status .codeEditor-status-worker-cell.ace_gutter-cell {
+        background-position: 0px center; 
+}
+
+.codeEditor-status-worker {
+       padding: 0 0.3em;
+       cursor: pointer;
+       display: table-cell;
+       *float: left;
+       *width: 10em;
+}
+
+.codeEditor-status-message {
+       border-left: 1px solid silver;  
+       border-right: 1px solid silver;
+       padding: 0 0.3em;
+       width: 100%;
+       display: table-cell;
+       *float: left;
+       *width: auto;
+}
+
+.codeEditor-status-line {
+       padding: 0 0.3em;
+       text-align: right;
+       white-space: nowrap;
+       display: table-cell;
+       *float: right;
+       *width: 4em;
+}
diff --git a/modules/jquery.codeEditor.js b/modules/jquery.codeEditor.js
index ede9eb6..7223a0a 100644
--- a/modules/jquery.codeEditor.js
+++ b/modules/jquery.codeEditor.js
@@ -221,6 +221,8 @@
                                                }
                                        } );
 
+                                       context.fn.setupStatusBar();
+
                                        summary = $( '#wpSummary' );
                                        // Let modules know we're ready to 
start working with the content
                                        context.fn.trigger( 'ready' );
@@ -242,6 +244,7 @@
                                // @todo fetch cursor, scroll position
 
                                // Drop the fancy editor widget...
+                               context.fn.removeStatusBar();
                                context.$codeEditorContainer.remove();
                                context.$codeEditorContainer = undefined;
                                context.$iframe = undefined;
@@ -276,7 +279,177 @@
                                }
 
                                onHashChange();
-                               $( window ).bind( 'hashchange', onHashChange );
+                               $( window ).on( 'hashchange', onHashChange );
+                       },
+                       /**
+                        * This creates a Statusbar, that allows you to see a 
count of the  
+                        */
+                       'setupStatusBar': function ( ) {
+                               var shouldUpdateAnnotations,
+                                       shouldUpdateSelection,
+                                       shouldUpdateLineInfo,
+                                       nextAnnotation,
+                                       delayedUpdate,
+                                       editor = context.codeEditor,
+                                       lang = require( 'ace/lib/lang' ),
+                                       $errors = $( '<span 
class="codeEditor-status-worker-cell ace_gutter-cell ace_error">0</span>' ),
+                                       $warnings = $( '<span 
class="codeEditor-status-worker-cell ace_gutter-cell ace_warning">0</span>' ),
+                                       $infos = $( '<span 
class="codeEditor-status-worker-cell ace_gutter-cell ace_info">0</span>' ),
+                                       $message = $( '<div/>' ).addClass( 
'codeEditor-status-message' ),
+                                       $lineAndMode = $( '<div/>' ).addClass( 
'codeEditor-status-line' ),
+                                       $workerStatus = $( '<div/>' )
+                                               .addClass( 
'codeEditor-status-worker' )
+                                               .append( $errors )
+                                               .append( $warnings )
+                                               .append( $infos );
+
+                               context.$statusBar = $( '<div/>' )
+                                       .addClass( 'codeEditor-status' )
+                                       .append( $workerStatus )
+                                       .append( $message )
+                                       .append( $lineAndMode );
+
+                               // Function to delay/debounce updates for the 
StatusBar
+                               delayedUpdate = lang.delayedCall( function() {
+                                       updateStatusBar( editor );
+                               }.bind( this ) );
+
+                               /**
+                                * Click handler that allows you to skip to the 
next annotation
+                                */
+                               $workerStatus.on( 'click', function( e ) {
+                                       if( nextAnnotation ) {
+                                               context.codeEditor.navigateTo( 
nextAnnotation.row, nextAnnotation.column );
+                                               // Scroll up a bit to give some 
context
+                                               context.codeEditor.scrollToRow( 
nextAnnotation.row - 3 );
+                                               e.preventDefault();
+                                       }
+                               } );
+
+                               /* Help function to concatenate strings with 
different separators */
+                               function addToStatus( status, str, separator ) {
+                                       if ( str ) {
+                                               status.push( str, separator || 
'|' );
+                                       }
+                               }
+
+                               /**
+                                * Update all the information in the status bar
+                                */
+                               function updateStatusBar() {
+                                       var annotation,
+                                               errors = 0,
+                                               warnings = 0,
+                                               infos = 0,
+                                               distance = NaN,
+                                               shortestDistance = Infinity,
+                                               closestAnnotation,
+                                               currentLine = 
editor.selection.lead.row,
+                                               annotations = 
context.codeEditor.getSession().getAnnotations();
+
+                                       // Reset the next annotation
+                                       nextAnnotation = null;
+
+                                       for ( var i = 0; i < 
annotations.length; i++ ) {
+                                               annotation = annotations[i];
+                                               distance = Math.abs( 
currentLine - annotation.row );
+
+                                               if ( distance < 
shortestDistance ) {
+                                                       shortestDistance = 
distance;
+                                                       closestAnnotation = 
annotation;
+                                               }
+                                               if ( nextAnnotation === null && 
annotation.row > currentLine ) {
+                                                       nextAnnotation = 
annotation;
+                                               }
+
+                                               switch ( annotations[i].type ) {
+                                                       case 'error':
+                                                               errors++;
+                                                               break;
+                                                       case 'warning':
+                                                               warnings++;
+                                                               break;
+                                                       case 'info':
+                                                               infos++;
+                                                               break;
+                                               }
+                                       }
+                                       // Wrap around to the beginning for 
nextAnnotation
+                                       if ( nextAnnotation === null && 
annotations.length > 0 ) {
+                                               nextAnnotation = annotations[0];
+                                       }
+                                       // Update the annotation counts
+                                       if ( shouldUpdateAnnotations ) {
+                                               $errors.text( errors );
+                                               $warnings.text( warnings );
+                                               $infos.text( infos );
+                                       }
+
+                                       // Show the message of the current 
line, if we have not already done so
+                                       if ( closestAnnotation &&
+                                                       currentLine === 
closestAnnotation.row &&
+                                                       closestAnnotation !== 
$message.data( 'annotation') ) {
+                                               $message.data( 'annotation', 
closestAnnotation );
+                                               $message.text( $.ucFirst( 
closestAnnotation.type ) + ': ' + closestAnnotation.text );
+                                       } else if ( null !== $message.data( 
'annotation' ) && ( closestAnnotation && currentLine !== closestAnnotation.row 
) ) {
+                                               // If we are on a different 
line without an annotation, then blank the message
+                                               $message.data( 'annotation', 
null );
+                                               $message.text( '' );
+                                       }
+
+                                       // The cursor position has changed
+                                       if ( shouldUpdateSelection || 
shouldUpdateLineInfo ) {
+                                               // Adapted from Ajax.org's 
ace/ext/statusbar module
+                                               var status = [];
+
+
+
+                                               if ( editor.$vimModeHandler ) {
+                                                       addToStatus( status, 
editor.$vimModeHandler.getStatusText() );
+                                               } else if ( 
editor.commands.recording ) {
+                                                       addToStatus( status, 
'REC' );
+                                               }
+
+                                               var c = editor.selection.lead;
+                                               addToStatus( status, ( c.row + 
1 ) + ':' + c.column, '');
+                                               if ( 
!editor.selection.isEmpty() ) {
+                                                       var r = 
editor.getSelectionRange();
+                                                       addToStatus( status, 
'(' + ( r.end.row - r.start.row ) + ':'  + ( r.end.column - r.start.column ) + 
')' );
+                                               }
+                                               status.pop();
+                                               $lineAndMode.text( 
status.join('') );
+                                       }
+
+                                       shouldUpdateLineInfo = 
shouldUpdateSelection = shouldUpdateAnnotations = false;
+                               }
+
+                               editor.getSession().on( 'changeAnnotation', 
function() {
+                                       shouldUpdateAnnotations = true;
+                                       delayedUpdate.schedule( 100 );
+                               } );
+                               editor.on( 'changeStatus', function() {
+                                       shouldUpdateLineInfo = true;
+                                       delayedUpdate.schedule( 100 );
+                               } );
+                               editor.on( 'changeSelection', function() {
+                                       shouldUpdateSelection = true;
+                                       delayedUpdate.schedule( 100 );
+                               } );
+
+                               // Force update
+                               shouldUpdateLineInfo = shouldUpdateSelection = 
shouldUpdateAnnotations = true;
+                               updateStatusBar( editor );
+
+                               context.$statusBar.insertAfter( $( 
'.wikiEditor-ui-view' ) );
+                       },
+                       removeStatusBar: function() {
+                               context.codeEditor.getSession().removeListener( 
'changeAnnotation' );
+                               context.codeEditor.removeListener( 
'changeSelection' );
+                               context.codeEditor.removeListener( 
'changeStatus' );
+                               context.nextAnnotation = null;
+                               context.$statusBar = null;
+
+                               $('.codeEditor-status').remove();
                        }
 
                } );

-- 
To view, visit https://gerrit.wikimedia.org/r/122601
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ided0804d5eb7864452287087dd1cf5a3dd8ff078
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/CodeEditor
Gerrit-Branch: master
Gerrit-Owner: TheDJ <hartman.w...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to