Henning Snater has uploaded a new change for review.

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


Change subject: (bug 48145) Simplified input extender widget
......................................................................

(bug 48145) Simplified input extender widget

Change-Id: I7091801e90f0f665be4de3634847fdf054ea7b86
---
M ValueView/ValueView.resources.mw.php
M ValueView/resources/jquery.ui/jquery.ui.inputextender.css
M ValueView/resources/jquery.ui/jquery.ui.inputextender.js
M ValueView/resources/jquery.ui/jquery.ui.listrotator.js
M ValueView/resources/jquery.valueview/valueview.css
M ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
M ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js
7 files changed, 81 insertions(+), 206 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DataValues 
refs/changes/86/62586/1

diff --git a/ValueView/ValueView.resources.mw.php 
b/ValueView/ValueView.resources.mw.php
index 145f856..d5b9776 100644
--- a/ValueView/ValueView.resources.mw.php
+++ b/ValueView/ValueView.resources.mw.php
@@ -105,6 +105,7 @@
                        ),
                        'dependencies' => array(
                                'jquery.eachchange',
+                               'jquery.ui.position',
                                'jquery.ui.widget',
                        ),
                        'messages' => array(
diff --git a/ValueView/resources/jquery.ui/jquery.ui.inputextender.css 
b/ValueView/resources/jquery.ui/jquery.ui.inputextender.css
index 4554dff..c355404 100644
--- a/ValueView/resources/jquery.ui/jquery.ui.inputextender.css
+++ b/ValueView/resources/jquery.ui/jquery.ui.inputextender.css
@@ -5,25 +5,12 @@
  * @author H. Snater < [email protected] >
  */
 
-.ui-inputextender .ui-inputextender-input {
-       display: inline;
-}
-
-.ui-inputextender .ui-inputextender-extender {
-       display: inline;
-}
-
-.ui-inputextender .ui-inputextender-contentcontainer {
+.ui-inputextender-extension {
        position: absolute;
-       z-index: 1;
-       left: 2px;
-       font-size: 84%;
        padding: 2px;
-       box-shadow: 2px 2px 6px -1px grey;
+       font-size: 84%
 }
 
-.ui-inputextener .ui-inputextender-extendedcontent {
-       margin-top: 5px;
-       padding-top: 5px;
-       border-top: 1px dashed #CCC;
+.ui-inputextender-extension > * {
+       font-size: 84%;
 }
diff --git a/ValueView/resources/jquery.ui/jquery.ui.inputextender.js 
b/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
index b925a15..1349c16 100644
--- a/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
+++ b/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
@@ -69,6 +69,13 @@
                return ( IS_MODULE_LOADED ) ? mw.msg( msgKey ) : string;
        }
 
+       /**
+        * Caches whether the widget is used in a rtl context. This, however, 
depends on using an "rtl"
+        * class on the document body like it is done in MediaWiki.
+        * @type {boolean}
+        */
+       var isRtl = $( 'body' ).hasClass( 'rtl' );
+
        $.widget( 'ui.inputextender', {
                /**
                 * Additional options
@@ -79,6 +86,11 @@
                        extendedContent: [],
                        initCallback: null,
                        hideWhenInputEmpty: true,
+                       position: {
+                               my: ( isRtl ) ? 'right top' : 'left top',
+                               at: ( isRtl ) ? 'right bottom' : 'left bottom',
+                               collision: 'none'
+                       },
                        messages: {
                                'show options': mwMsgOrString( 
'valueview-inputextender-showoptions', 'show options' ),
                                'hide options': mwMsgOrString( 
'valueview-inputextender-hideoptions', 'hide options' )
@@ -86,46 +98,10 @@
                },
 
                /**
-                * The widget parent's node.
+                * The input extension's node.
                 * @type {jQuery}
                 */
-               $parent: null,
-
-               /**
-                * Container node wrapping the widget's whole DOM structure.
-                * @type {jQuery}
-                */
-               $container: null,
-
-               /**
-                * Container node containing the input element and the extender.
-                * @type {jQuery}
-                */
-               $inputContainer: null,
-
-               /**
-                * Node of the link to extended the extenders additional 
content.
-                * @type {jQuery}
-                */
-               $extender: null,
-
-               /**
-                * Node containing all the extension content.
-                * @type {jQuery}
-                */
-               $contentContainer: null,
-
-               /**
-                * Node of the default/"fixed" extension content.
-                * @type {jQuery}
-                */
-               $content: null,
-
-               /**
-                * Node of the additional extension content shown/hidden by the 
extender link.
-                * @type {jQuery}
-                */
-               $extendedContent: null,
+               $extension: null,
 
                /**
                 * Caches the timeout when the actual "blur" action should kick 
in.
@@ -139,78 +115,43 @@
                _create: function() {
                        var self = this;
 
-                       this.$parent = this.element.parent();
+                       this.element
+                       .addClass( this.widgetBaseClass + '-input' );
 
-                       if( !this.$parent.length ) {
-                               throw new Error( 'Input extender widget needs 
to be in the DOM when initializing.' );
-                       }
-
-                       this.$container = $( '<div/>' )
-                       .addClass( this.widgetBaseClass )
-                       .appendTo( this.$parent );
-
-                       this.$inputContainer = $( '<div />' )
-                       .addClass( this.widgetBaseClass + '-inputcontainer' )
-                       .append( this.element.addClass( this.widgetBaseClass + 
'-input' ).detach() )
-                       .appendTo( this.$container );
-
-                       this.$extender = $( '<a/>' )
-                       .addClass( this.widgetBaseClass + '-extender' )
-                       .attr( 'href', 'javascript:void(0);' )
-                       .text( this.options.messages['show options'] )
-                       .appendTo( this.$inputContainer )
+                       this.$extension = $( '<div/>' )
+                       .addClass( this.widgetBaseClass + '-extension 
ui-widget-content' )
                        .on( 'click', function( event ) {
                                clearTimeout( self._blurTimeout );
-                               self._toggleExtension();
+                               event.stopPropagation();
+                               self.showExtension();
                        } )
-                       .on( 'keydown', function( event ) {
-                               if( event.keyCode === $.ui.keyCode.ENTER ) {
-                                       clearTimeout( self._blurTimeout );
-                                       self._toggleExtension();
-                               }
-                       } )
-                       .on( 'focus', function( event ) {
-                               clearTimeout( self._blurTimeout );
-                       } )
-                       .hide();
+                       .appendTo( $( 'body' ) );
 
-                       this.$contentContainer = $( '<div/>' )
-                       .addClass( this.widgetBaseClass + '-contentcontainer 
ui-widget-content' )
-                       .appendTo( this.$container )
-                       .on( 'click.' + this.widgetName, function( event ) {
-                               clearTimeout( self._blurTimeout );
-                       } );
-
-                       this.$content = $( '<div/>' )
-                       .addClass( this.widgetBaseClass + '-content' )
-                       .appendTo( this.$contentContainer );
-
-                       this.$extendedContent = $( '<div/>' )
-                       .addClass( this.widgetBaseClass + '-extendedcontent' )
-                       .appendTo( this.$contentContainer );
-
-                       this.element.add( this.$extender )
+                       this.element
                        .on( 'focus.' + this.widgetName, function( event ) {
                                if( !self.options.hideWhenInputEmpty || 
self.element.val() !== '' ) {
                                        clearTimeout( self._blurTimeout );
-                                       self.showContent();
+                                       self.showExtension();
                                }
                        } )
-                       // TODO: Do not hide when tabbing into the 
inputextender's contents
+                       // TODO: Allow direct tabbing into the extension
                        .on( 'blur.' + this.widgetName, function( event ) {
                                self._blurTimeout = setTimeout( function() {
-                                       self.hideContent( function() {
-                                               self._toggleExtension( { 
forceHide: true } );
-                                       } );
+                                       self.hideExtension();
                                }, 150 );
+                       } )
+                       .on( 'keydown.' + this.widgetName, function( event ) {
+                               if( event.keyCode === $.ui.keyCode.ESCAPE ) {
+                                       self.hideExtension();
+                               }
                        } );
 
                        if( this.options.hideWhenInputEmpty ) {
                                this.element.eachchange( function( event, 
oldValue ) {
-                                       if( self.element.val() === '' && 
!self.$extendedContent.is( ':visible' ) ) {
-                                               self.hideContent();
+                                       if( self.element.val() === '' ) {
+                                               self.hideExtension();
                                        } else if ( oldValue === '' ) {
-                                               self.showContent();
+                                               self.showExtension();
                                        }
                                } );
                        }
@@ -222,10 +163,8 @@
                                        var $widgetNodes = $( ':' + 
self.widgetBaseClass );
                                        $widgetNodes.each( function( i, 
widgetNode ) {
                                                var widget = $( widgetNode 
).data( self.widgetName );
-                                               if( $( event.target ).closest( 
widget.$container ).length === 0 ) {
-                                                       widget.hideContent( 
function() {
-                                                               
widget._toggleExtension( { forceHide: true } );
-                                                       } );
+                                               if( $( event.target ).closest( 
widget.$extension.add( widget.element ) ).length === 0 ) {
+                                                       widget.hideExtension();
                                                }
                                        } );
                                } );
@@ -237,17 +176,14 @@
                                this.options.initCallback();
                        }
 
-                       this.$contentContainer.hide();
-                       this.$extendedContent.hide();
+                       this.$extension.hide();
                },
 
                /**
                 * @see jQuery.Widget.destroy
                 */
                destroy: function() {
-                       var $input = this.element.detach();
-                       this.$container.remove();
-                       this.$parent.append( $input );
+                       this.$extension.remove();
                        if( $( ':' + this.widgetBaseClass ).length === 0 ) {
                                $( 'html' ).off( '.' + this.widgetName );
                        }
@@ -255,71 +191,34 @@
                },
 
                /**
-                * Draws the widget according to its current state.
+                * Draws the widget.
                 */
                _draw: function() {
                        var self = this;
 
-                       this.$content.empty();
-
-                       // Only show the extender when there are any additional 
options to extend:
-                       this.$extender[ ( this.options.extendedContent.length ) 
? 'show' : 'hide' ]();
+                       this.$extension.empty();
 
                        $.each( this.options.content, function( i, $node ) {
-                               self.$content.append( $node );
-                       } );
-
-                       $.each( this.options.extendedContent, function( i, 
$node ) {
-                               self.$extendedContent.append( $node );
+                               self.$extension.append( $node );
                        } );
                },
 
                /**
-                * Toggles the visibility of the additional options.
-                *
-                * @param {Object|undefined} customOptions
-                */
-               _toggleExtension: function( customOptions ) {
-                       var self = this,
-                               options = {
-                                       moveFocus: true,
-                                       forceHide: false
-                               };
-
-                       $.extend( options, customOptions );
-
-                       function hideExtendedContent() {
-                               self.$extendedContent.slideUp( 150, function() {
-                                       self.$extender.text( 
self.options.messages['show options'] );
-                                       self._trigger( 'toggle' );
-                               } );
-                       }
-
-                       if( options.forceHide ) {
-                               hideExtendedContent();
-                               return;
-                       }
-
-                       if( this.$extendedContent.is( ':visible' ) ) {
-                               this.showContent( hideExtendedContent );
-                       } else {
-                               this.showContent( function() {
-                                       self.$extendedContent.slideDown( 150, 
function() {
-                                               self.$extender.text( 
self.options.messages['hide options'] );
-                                               self._trigger( 'toggle' );
-                                       } );
-                               } );
-                       }
-
-               },
-
-               /**
-                * Shows all the extension contents.
+                * Shows the extension.
                 *
                 * @param {Function} [callback] Invoked as soon as the contents 
are visible.
                 */
-               showContent: function( callback ) {
-                       this.$contentContainer.stop( true, true ).fadeIn( 150, 
function() {
+               showExtension: function( callback ) {
+                       // Element needs to be visible to use 
jquery.ui.position.
+                       if( !this.$extension.is( ':visible' ) ) {
+                               this.$extension.show();
+                               this.$extension.position( $.extend( {
+                                       of: this.element
+                               }, this.options.position ) );
+                               this.$extension.hide();
+                       }
+
+                       this.$extension.stop( true, true ).fadeIn( 150, 
function() {
                                if( $.isFunction( callback ) ) {
                                        callback();
                                }
@@ -327,12 +226,12 @@
                },
 
                /**
-                * Hides all the extension contents.
+                * Hides the extension.
                 *
                 * @param {Function} [callback] Invoked as soon as the contents 
are hidden.
                 */
-               hideContent: function( callback ) {
-                       this.$contentContainer.stop( true, true ).fadeOut( 150, 
function() {
+               hideExtension: function( callback ) {
+                       this.$extension.stop( true, true ).fadeOut( 150, 
function() {
                                if( $.isFunction( callback ) ) {
                                        callback();
                                }
diff --git a/ValueView/resources/jquery.ui/jquery.ui.listrotator.js 
b/ValueView/resources/jquery.ui/jquery.ui.listrotator.js
index 86411ab..6c28a34 100644
--- a/ValueView/resources/jquery.ui/jquery.ui.listrotator.js
+++ b/ValueView/resources/jquery.ui/jquery.ui.listrotator.js
@@ -175,7 +175,7 @@
                                self._trigger( 'auto' );
                        } )
                        .addClass( 'ui-state-active' );
-                       this.$auto.children( 'a' ).text( 
this.options.messages['show options'] );
+                       this.$auto.children( 'a' ).text( 
this.options.messages['auto'] );
 
                        // Construct the basic sections:
                        this.$curr = this._createSection( 'curr', function( 
event ) {
diff --git a/ValueView/resources/jquery.valueview/valueview.css 
b/ValueView/resources/jquery.valueview/valueview.css
index 6bdf022..faa1393 100644
--- a/ValueView/resources/jquery.valueview/valueview.css
+++ b/ValueView/resources/jquery.valueview/valueview.css
@@ -39,16 +39,16 @@
        background-color: white;
 }
 
-.valueview .valueview-preview-value {
-       font-size: 119%; /* Reset to default 100% */
-}
-
-.valueview .valueview-preview-novalue {
-       font-style: italic;
-}
-
 .valueview-ineditmode.linkedsingleinputvalueview a,
 .valueview-ineditmode.linkedsingleinputvalueview a {
        /* make sure input box which still is inside a doesn't display text as 
links */
        color: inherit;
 }
+
+.valueview-preview-value {
+       font-size: 119%; /* Reset to default 100% */
+}
+
+.valueview-preview-novalue {
+       font-style: italic;
+}
diff --git 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
index 9a63885..b4001ad 100644
--- 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
+++ 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
@@ -106,8 +106,7 @@
                        // TODO: Move input extender out of here to a more 
generic place since it is not
                        // TimeInput specific.
                        .inputextender( {
-                               content: [ this.$preview ],
-                               extendedContent: [ this.$precision ],
+                               content: [ this.$preview, this.$precision ],
                                initCallback: function() {
                                        self.$precision.data( 'listrotator' 
).initWidths();
                                }
diff --git a/ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js 
b/ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js
index fc263d7..c298382 100644
--- a/ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js
+++ b/ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js
@@ -18,8 +18,7 @@
        var newTestInputextender = function( options ) {
                if( !options ) {
                        options = {
-                               content: [ $( '<span/>' ).addClass( 
'defaultContent' ).text( 'default content' ) ],
-                               extendedContent: [ $( '<span/>' ).addClass( 
'extendedContent' ).text( 'extended content' ) ]
+                               content: [ $( '<span/>' ).addClass( 
'defaultContent' ).text( 'default content' ) ]
                        }
                }
 
@@ -45,33 +44,23 @@
                expect( 1 );
 
                assert.ok(
-                       !extender.$contentContainer.is( ':visible' ),
-                       'Content is not visible.'
+                       !extender.$extension.is( ':visible' ),
+                       'Extension is not visible.'
                );
        } );
 
-       QUnit.test( 'Show/Hide basic content', function( assert ) {
+       QUnit.test( 'Show/Hide', function( assert ) {
                var $input = newTestInputextender(),
                        extender = $input.data( 'inputextender' );
 
-               expect( 4 );
+               expect( 2 );
 
                stop();
 
-               extender.showContent( function() {
+               extender.showExtension( function() {
                        assert.ok(
-                               extender.$contentContainer.is( ':visible' ),
-                               'Content visible after focusing input element.'
-                       );
-
-                       assert.ok(
-                               extender.$content.is( ':visible' ),
-                               'Default content is visible.'
-                       );
-
-                       assert.ok(
-                               !extender.$extendedContent.is( ':visible' ),
-                               'Additional content is hidden.'
+                               extender.$extension.is( ':visible' ),
+                               'showExtension()'
                        );
 
                        start();
@@ -79,10 +68,10 @@
 
                stop();
 
-               extender.hideContent( function() {
+               extender.hideExtension( function() {
                        assert.ok(
-                               !extender.$contentContainer.is( ':visible' ),
-                               'Content is hidden after blurring the input 
element.'
+                               !extender.$extension.is( ':visible' ),
+                               'hideExtension()'
                        );
 
                        start();

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I7091801e90f0f665be4de3634847fdf054ea7b86
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/DataValues
Gerrit-Branch: master
Gerrit-Owner: Henning Snater <[email protected]>

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

Reply via email to