jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/354450 )

Change subject: rebaser: Tidy up author list UI
......................................................................


rebaser: Tidy up author list UI

* Use more OOUI widgets
* Don't hide cursor after 2s, add a class after 5s. This could
  be used to hide user label and/or grey out cursor.
* Ensure authorId is always a number.

Change-Id: I3a41c1da74352750a8d175637e6355e53b25dc7a
---
M demos/ve/demo.css
M rebaser/demo.js
M rebaser/server.js
M rebaser/views/editor.ejs
M src/ce/styles/ve.ce.Surface.css
M src/ce/ve.ce.Surface.js
M src/dm/ve.dm.SurfaceSynchronizer.js
7 files changed, 109 insertions(+), 63 deletions(-)

Approvals:
  Catrope: Looks good to me, but someone else must approve
  jenkins-bot: Verified
  Jforrester: Looks good to me, approved



diff --git a/demos/ve/demo.css b/demos/ve/demo.css
index 5a70bfc..8ad3b0c 100644
--- a/demos/ve/demo.css
+++ b/demos/ve/demo.css
@@ -22,6 +22,35 @@
        background-size: contain;
 }
 
+.ve-pad-menu {
+       float: right;
+       margin-top: 1em;
+}
+
+.ve-pad-menu > .oo-ui-fieldLayout {
+       width: 20em;
+}
+
+.ve-pad-menu > .oo-ui-fieldLayout,
+.ve-pad-menu > .oo-ui-popupButtonWidget {
+       margin-right: 1em;
+       display: inline-block;
+       vertical-align: top;
+}
+
+.ve-pad-menu-author {
+       pointer-events: none;
+}
+
+.ve-pad-menu-author.oo-ui-iconElement .oo-ui-iconElement-icon {
+       top: 0.3em;
+       height: 1.875em;
+}
+
+.ve-pad-menu-author-self .oo-ui-labelElement-label {
+       font-weight: bold;
+}
+
 .ve-pad-logo {
        background-image: url( VisualEditor-pad-logo.svg );
        width: 8.5em;
diff --git a/rebaser/demo.js b/rebaser/demo.js
index 5d47eeb..9a6b129 100644
--- a/rebaser/demo.js
+++ b/rebaser/demo.js
@@ -6,78 +6,81 @@
 
 new ve.init.sa.Platform( ve.messagePaths ).initialize().done( function () {
        var synchronizer,
+               updatingName = false,
                $editor = $( '.ve-demo-editor' ),
-               $sidebar = $( '<div>' ),
+               $menu = $( '.ve-pad-menu' ),
                nameInput = new OO.ui.TextInputWidget(),
-               changeNameButton = new OO.ui.ButtonWidget( { label: 'Change 
name' } ),
-               authorList = new OO.ui.SelectWidget(),
+               editNameLayout = new OO.ui.FieldLayout( nameInput, { align: 
'right', label: 'Name' } ),
+               oldName = '',
+               $authorList = $( '<div>' ),
+               authorLabels = {},
+               userPopup = new OO.ui.PopupButtonWidget( {
+                       label: 'Users',
+                       indicator: 'down',
+                       popup: {
+                               label: 'Users',
+                               $content: $authorList,
+                               padded: true,
+                               align: 'center'
+                       }
+               } ),
                // eslint-disable-next-line new-cap
                target = new ve.demo.target();
 
        function updateName() {
-               synchronizer.changeName( nameInput.getValue() );
+               if ( !updatingName ) {
+                       synchronizer.changeName( nameInput.getValue() );
+               }
        }
 
-       $sidebar.append(
-               // FIXME FieldLayouts exist for this purpose
-               nameInput.$element
-                       .css( { display: 'inline-block', width: 'auto' } ),
-               changeNameButton.$element,
-               authorList.$element
+       $menu.append(
+               editNameLayout.$element,
+               userPopup.$element
        );
 
-       $editor
-               .append(
-                       $( '<div>' )
-                               .css( { display: 'table', width: '100%' } )
-                               .append(
-                                       $( '<div>' )
-                                               .css( { display: 'table-row' } )
-                                               .append(
-                                                       $( '<div>' )
-                                                               .css( { 
display: 'table-cell', width: '80%' } )
-                                                               .append( 
target.$element ),
-                                                       $sidebar
-                                                               .css( { 
display: 'table-cell', 'padding-left': '1em' } )
-                                               )
-                               )
-               );
+       $editor.append( target.$element );
+
        target.addSurface( ve.dm.converter.getModelFromDom( 
ve.createDocumentFromHtml( '' ) ) );
        synchronizer = new ve.dm.SurfaceSynchronizer( target.surface.model, 
ve.docName );
        target.surface.view.setSynchronizer( synchronizer );
 
        synchronizer.on( 'authorNameChange', function ( authorId ) {
-               var color,
-                       authorLabel = authorList.getItemFromData( String( 
authorId ) );
-               if ( !authorLabel ) {
-                       // FIXME: Duplicated from SurfaceSynchronizer
-                       color = '#' +
-                               ( 8 * ( 1 - Math.sin( 5 * authorId ) ) 
).toString( 16 ).slice( 0, 1 ) +
-                               ( 6 * ( 1 - Math.cos( 3 * authorId ) ) 
).toString( 16 ).slice( 0, 1 ) +
-                               '0';
+               var authorLabel = authorLabels[ authorId ],
+                       newName = synchronizer.authorNames[ authorId ];
 
+               if ( !authorLabel ) {
                        // FIXME use something more suitable than 
DecoratedOptionWidget
                        authorLabel = new OO.ui.DecoratedOptionWidget( {
-                               data: String( authorId ),
+                               classes: [ 've-pad-menu-author' ],
                                // HACK: force the icon to show, but override 
the background with a color
                                icon: 'none'
                        } );
-                       authorLabel.$icon.css( 'background', color );
-                       authorList.addItems( [ authorLabel ] );
+                       authorLabel.$icon.css( 'background', '#' + 
synchronizer.constructor.static.getAuthorColor( authorId ) );
+                       authorLabels[ authorId ] = authorLabel;
+                       $authorList.append( authorLabel.$element );
                }
-               authorLabel.setLabel( String( synchronizer.authorNames[ 
authorId ] ) );
-               if ( String( authorId ) === String( synchronizer.author ) ) {
-                       nameInput.setValue( String( synchronizer.authorNames[ 
authorId ] ) );
+               authorLabel.setLabel( newName );
+               if ( authorId === synchronizer.author ) {
+                       // Ensure you are at the top of the list
+                       $authorList.prepend( authorLabel.$element.addClass( 
've-pad-menu-author-self' ) );
+                       // Don't update nameInput if the user is still changing 
it
+                       if ( nameInput.getValue() === oldName ) {
+                               // Don't send this "new" name back to the server
+                               updatingName = true;
+                               nameInput.setValue( newName );
+                               updatingName = false;
+                       }
                }
+               oldName = newName;
        } );
 
        synchronizer.on( 'authorDisconnect', function ( authorId ) {
-               var authorLabel = authorList.getItemFromData( String( authorId 
) );
+               var authorLabel = authorLabels[ authorId ];
                if ( authorLabel ) {
-                       authorList.removeItems( [ authorLabel ] );
+                       authorLabel.$element.remove();
+                       delete authorLabels[ authorId ];
                }
        } );
 
-       changeNameButton.on( 'click', updateName );
-       nameInput.on( 'enter', updateName );
+       nameInput.on( 'change', ve.debounce( updateName, 250 ) );
 } );
diff --git a/rebaser/server.js b/rebaser/server.js
index 755254a..c797472 100644
--- a/rebaser/server.js
+++ b/rebaser/server.js
@@ -39,7 +39,7 @@
                        author = 1 + ( lastAuthorForDoc.get( docName ) || 0 ),
                        authorData = rebaseServer.getAuthorData( docName, 
author );
                lastAuthorForDoc.set( docName, author );
-               rebaseServer.setAuthorName( docName, author, 'Anonymous coward 
' + author );
+               rebaseServer.setAuthorName( docName, author, 'User ' + author 
); // TODO: i18n
                logServerEvent( {
                        type: 'newClient',
                        doc: docName,
diff --git a/rebaser/views/editor.ejs b/rebaser/views/editor.ejs
index 7870522..1ae80b3 100644
--- a/rebaser/views/editor.ejs
+++ b/rebaser/views/editor.ejs
@@ -36,6 +36,7 @@
        </head>
        <body>
                <div class="ve-pad-logo"></div>
+               <div class="ve-pad-menu"></div>
                <div style="clear: both;"></div>
                <div class="ve-demo-editor"></div>
 
diff --git a/src/ce/styles/ve.ce.Surface.css b/src/ce/styles/ve.ce.Surface.css
index a9402dc..a95f902 100644
--- a/src/ce/styles/ve.ce.Surface.css
+++ b/src/ce/styles/ve.ce.Surface.css
@@ -83,6 +83,11 @@
        text-overflow: ellipsis;
 }
 
+.ve-ce-surface-highlights-user-cursor-inactive,
+.ve-ce-surface-highlights-user-selection-inactive {
+       opacity: 0.5;
+}
+
 .ve-ce-surface-paste {
        position: fixed;
        /* FIXME T126024: Stop the viewport scrolling when the paste target is 
typed into */
diff --git a/src/ce/ve.ce.Surface.js b/src/ce/ve.ce.Surface.js
index 8eb9632..d3020d2 100644
--- a/src/ce/ve.ce.Surface.js
+++ b/src/ce/ve.ce.Surface.js
@@ -3983,11 +3983,7 @@
  * @param {number} author The author ID
  */
 ve.ce.Surface.prototype.onSynchronizerAuthorUpdate = function ( author ) {
-       try {
-               this.paintAuthor( author );
-       } catch ( error ) {
-               return;
-       }
+       this.paintAuthor( author );
 };
 
 /**
@@ -3997,10 +3993,7 @@
  */
 ve.ce.Surface.prototype.paintAuthor = function ( author ) {
        var i, l, rects, rect, overlays,
-               color = '#' +
-                       ( 8 * ( 1 - Math.sin( 5 * author ) ) ).toString( 16 
).slice( 0, 1 ) +
-                       ( 6 * ( 1 - Math.cos( 3 * author ) ) ).toString( 16 
).slice( 0, 1 ) +
-                       '0',
+               color = '#' + 
this.synchronizer.constructor.static.getAuthorColor( author ),
                selection = this.synchronizer.authorSelections[ author ];
 
        if ( author === this.author ) {
@@ -4011,22 +4004,23 @@
                this.userSelectionOverlays[ author ] = {
                        $cursor: $( '<div>' ),
                        $selection: $( '<div>' ),
-                       clearDebounced: ve.debounce( function () {
-                               overlays.$cursor.detach();
-                               overlays.$selection.detach();
-                       }, 2000 )
+                       deactivateDebounced: ve.debounce( function () {
+                               // TODO: Transition away the user label when 
inactive, maybe dim selection
+                               overlays.$cursor.addClass( 
've-ce-surface-highlights-user-cursor-inactive' );
+                               overlays.$selection.addClass( 
've-ce-surface-highlights-user-selection-inactive' );
+                       }, 5000 )
                };
        }
        overlays = this.userSelectionOverlays[ author ];
 
-       if ( selection.isNull() ) {
+       if ( !selection || selection.isNull() ) {
                overlays.$cursor.detach();
                overlays.$selection.detach();
                return;
        }
 
-       overlays.$cursor.empty();
-       overlays.$selection.empty();
+       overlays.$cursor.empty().removeClass( 
've-ce-surface-highlights-user-cursor-inactive' );
+       overlays.$selection.empty().removeClass( 
've-ce-surface-highlights-user-selection-inactive' );
 
        if ( !selection.isCollapsed() ) {
                rects = ve.ce.Selection.static.newFromModel( selection, this 
).getSelectionRects();
@@ -4063,7 +4057,7 @@
 
        this.$highlightsUserCursors.append( overlays.$cursor );
        this.$highlightsUserSelections.append( overlays.$selection );
-       overlays.clearDebounced();
+       overlays.deactivateDebounced();
 };
 
 /**
diff --git a/src/dm/ve.dm.SurfaceSynchronizer.js 
b/src/dm/ve.dm.SurfaceSynchronizer.js
index 2995b25..f313fe5 100644
--- a/src/dm/ve.dm.SurfaceSynchronizer.js
+++ b/src/dm/ve.dm.SurfaceSynchronizer.js
@@ -71,6 +71,20 @@
  * @param {string} author The author whose selection has changed
  */
 
+/* Static methods */
+
+/**
+ * TODO: Let authors choose color
+ *
+ * @param {number} authorId
+ * @return {string} Color, RRGGBB
+ */
+ve.dm.SurfaceSynchronizer.static.getAuthorColor = function ( authorId ) {
+       return ( 8 * ( 1 - Math.sin( 5 * authorId ) ) ).toString( 16 ).slice( 
0, 1 ) +
+               ( 6 * ( 1 - Math.cos( 3 * authorId ) ) ).toString( 16 ).slice( 
0, 1 ) +
+               '0';
+};
+
 /* Methods */
 
 /**
@@ -267,7 +281,7 @@
                return;
        }
        for ( authorId in data.names ) {
-               this.onNameChange( { authorId: authorId, authorName: 
data.names[ authorId ] } );
+               this.onNameChange( { authorId: +authorId, authorName: 
data.names[ authorId ] } );
        }
        history = ve.dm.Change.static.deserialize( data.history, this.doc );
        this.acceptChange( history );

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I3a41c1da74352750a8d175637e6355e53b25dc7a
Gerrit-PatchSet: 7
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to