jsMessage: Redesign in Vector/Monobook as bubble with auto-hide
authorTrevor Parscal <tparscal@wikimedia.org>
Fri, 3 Aug 2012 18:50:36 +0000 (11:50 -0700)
committerTimo Tijhof <ttijhof@wikimedia.org>
Sat, 11 Aug 2012 09:54:18 +0000 (11:54 +0200)
A bit like the "Growl" notifications on Mac.

The message will auto-hide in all skins, which is especially useful
with VisualEditor because you it does most things through ajax which
means that a msg in there could be visible for way longer than it
should be with no way of hiding it.

By being designed as a floating bubble instead of a static positioned
element in regular document flow it also prevents the page flow
from being interrupted and moved down a bit. Again that was
especially annoying in VisualEditor because jsMessage forced itself
between the tab bar and the editor toolbar, which were meant to be
against each other.

Auto-hiding is disabled while the mouse if hovering the message.
The timer starts again when the mouse is no longer on it.

Also:
* cleaned up some whitespace issues in vector.js
* Removed jshintignore for skins/common
  Removed whitelisting of 'mw' global
  skins/common may not be prefect, but at least this way it gives
  warnings inside the code when writing/editing something, which is
  still useful.
  It helped to catch that 'mw' was used from the global scope.

Change-Id: I41c70d78c8ed8aeb91a598dc4a7b26dfad8d8f6c

.jshintignore
.jshintrc
RELEASE-NOTES-1.20
resources/mediawiki/mediawiki.util.js
skins/common/shared.css
skins/common/wikibits.js
skins/monobook/main.css
skins/vector/screen.css
skins/vector/vector.js

index 8ba7fc3..9534f97 100644 (file)
@@ -18,6 +18,3 @@ resources/jquery.ui
 resources/mediawiki.libs/mediawiki.libs.jpegmeta.js
 tests/jasmine/lib/jasmine-1.0.1/jasmine-html.js
 tests/jasmine/lib/jasmine-1.0.1/jasmine.js
-
-# legacy stuff
-skins/common
index efbe54d..4cf86b8 100644 (file)
--- a/.jshintrc
+++ b/.jshintrc
@@ -1,7 +1,6 @@
 {
        "predef": [
                "mediaWiki",
-               "mw",
                "QUnit"
        ],
 
index dfd747f..b904f41 100644 (file)
@@ -119,6 +119,7 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
 * HTMLForm mutators can now be chained (they return $this)
 * A new message, "api-error-filetype-banned-type", is available for formatting
   API upload errors due to the file extension blacklist.
+* jsMessage: Redesigned in Vector/Monobook as floating bubble with auto-hide.
 
 === Bug fixes in 1.20 ===
 * (bug 30245) Use the correct way to construct a log page title.
index c3e5e98..38c19c4 100644 (file)
@@ -5,7 +5,9 @@
        'use strict';
 
        // Local cache and alias
-       var util = {
+       var hideMessageTimeout,
+               messageBoxEvents = false,
+               util = {
 
                /**
                 * Initialisation
                 * @return {Boolean} True on success, false on failure.
                 */
                jsMessage: function ( message, className ) {
+                       var $messageDiv = $( '#mw-js-message' );
+
                        if ( !arguments.length || message === '' || message === null ) {
-                               $( '#mw-js-message' ).empty().hide();
+                               $messageDiv.empty().hide();
+                               stopHideMessageTimeout();
                                return true; // Emptying and hiding message is intended behaviour, return true
-
                        } else {
                                // We special-case skin structures provided by the software. Skins that
                                // choose to abandon or significantly modify our formatting can just define
                                // an mw-js-message div to start with.
-                               var $messageDiv = $( '#mw-js-message' );
                                if ( !$messageDiv.length ) {
                                        $messageDiv = $( '<div id="mw-js-message"></div>' );
                                        if ( util.$content.parent().length ) {
                                        }
                                }
 
+                               if ( !messageBoxEvents ) {
+                                       $messageDiv
+                                               .on( {
+                                                       'mouseenter': stopHideMessageTimeout,
+                                                       'mouseleave': startHideMessageTimeout,
+                                                       'click': function() {
+                                                               $(this).fadeOut( 'slow' );
+                                                       }
+                                               } )
+                                               .on( 'click', 'a', function ( e ) {
+                                                       // Prevent links, even those that don't exist yet, from causing the
+                                                       // message box to close when clicked
+                                                       e.stopPropagation();
+                                               } );
+                               }
+
                                if ( className ) {
-                                       $messageDiv.prop( 'class', 'mw-js-message-' + className );
+                                       $messageDiv.prop( 'className', 'mw-js-message-' + className );
                                }
 
                                if ( typeof message === 'object' ) {
                                }
 
                                $messageDiv.slideDown();
+                               startHideMessageTimeout();
                                return true;
                        }
                },
                }
        };
 
+       // Message auto-hide helpers
+       function hideMessage() {
+               $( '#mw-js-message' ).fadeOut( 'slow' );
+       }
+       function stopHideMessageTimeout() {
+               clearTimeout( hideMessageTimeout );
+       }
+       function startHideMessageTimeout() {
+               clearTimeout( hideMessageTimeout );
+               hideMessageTimeout = setTimeout( hideMessage, 5000 );
+       }
+
        mw.util = util;
 
 }( mediaWiki, jQuery ) );
index 8c114f0..8c35626 100644 (file)
@@ -116,14 +116,19 @@ span.texhtml {
 #wpTextbox1 {
        clear: both;
 }
+
 #toolbar img {
        cursor: pointer;
 }
+
 div#mw-js-message {
        margin: 1em 5%;
        padding: 0.5em 2.5%;
        border: solid 1px #ddd;
        background-color: #fcfcfc;
+       /* Message hides on-click */
+       /* See also mw.util.jsMessage */
+       cursor: pointer;
 }
 
 /* Edit section links */
index 8f47499..6526e8b 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * MediaWiki legacy wikibits
  */
-(function(){
+( function ( mw ) {
 
 window.clientPC = navigator.userAgent.toLowerCase(); // Get client info
 window.is_gecko = /gecko/.test( clientPC ) &&
@@ -515,55 +515,14 @@ window.redirectToFragment = function( fragment ) {
  * Add a cute little box at the top of the screen to inform the user of
  * something, replacing any preexisting message.
  *
- * @param message String -or- Dom Object  HTML to be put inside the right div
- * @param className String   Used in adding a class; should be different for each
- *   call to allow CSS/JS to hide different boxes.  null = no class used.
- * @return Boolean       True on success, false on failure
+ * @deprecated since 1.17 Use mw.util.jsMessage instead.
+ * @param {String|HTMLElement} message To be put inside the message box.
+ * @param {String} className Used in adding a class; Can be used to selectively
+ *  apply CSS to a certain category of messages.  null = no class used.
+ * @return {Boolean} True on success, false on failure
  */
-window.jsMsg = function( message, className ) {
-       if ( !document.getElementById ) {
-               return false;
-       }
-       // We special-case skin structures provided by the software.  Skins that
-       // choose to abandon or significantly modify our formatting can just define
-       // an mw-js-message div to start with.
-       var messageDiv = document.getElementById( 'mw-js-message' );
-       if ( !messageDiv ) {
-               messageDiv = document.createElement( 'div' );
-               if ( document.getElementById( 'column-content' )
-               && document.getElementById( 'content' ) ) {
-                       // MonoBook, presumably
-                       document.getElementById( 'content' ).insertBefore(
-                               messageDiv,
-                               document.getElementById( 'content' ).firstChild
-                       );
-               } else if ( document.getElementById( 'content' )
-               && document.getElementById( 'article' ) ) {
-                       // Non-Monobook but still recognizable (old-style)
-                       document.getElementById( 'article').insertBefore(
-                               messageDiv,
-                               document.getElementById( 'article' ).firstChild
-                       );
-               } else {
-                       return false;
-               }
-       }
-
-       messageDiv.setAttribute( 'id', 'mw-js-message' );
-       messageDiv.style.display = 'block';
-       if( className ) {
-               messageDiv.setAttribute( 'class', 'mw-js-message-' + className );
-       }
-
-       if ( typeof message === 'object' ) {
-               while ( messageDiv.hasChildNodes() ) { // Remove old content
-                       messageDiv.removeChild( messageDiv.firstChild );
-               }
-               messageDiv.appendChild( message ); // Append new content
-       } else {
-               messageDiv.innerHTML = message;
-       }
-       return true;
+window.jsMsg = function () {
+       return mw.util.jsMessage.apply( mw.util, arguments );
 };
 
 /**
@@ -663,4 +622,4 @@ if ( ie6_bugs ) {
        importScriptURI( mw.config.get( 'stylepath' ) + '/common/IEFixes.js' );
 }
 
-})();
+}( mediaWiki ) );
index 2fe259e..0566e98 100644 (file)
@@ -913,3 +913,17 @@ div.mw-lag-warn-high {
 .tipsy {
        font-size: 127%;
 }
+
+/* jsMessage */
+
+div#mw-js-message {
+       position: absolute;
+       margin: 0;
+       padding: 0.25em 1em;
+       right: 1em;
+       top: 1em;
+       width: 20em;
+       z-index: 10000;
+       -webkit-box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.125);
+       box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.125);
+}
index 32a6489..e74bd96 100644 (file)
@@ -784,8 +784,21 @@ div#content a.external[href *=".pdf?"], div#content a.external[href *=".PDF?"],
        position: relative;
        width: 100%;
 }
-#mw-js-message {
+div#mw-js-message {
+       background-color: #ffffff;
+       background-color: rgba(255, 255, 255, 0.93);
        font-size: 0.8em;
+       position: absolute;
+       margin: 0;
+       padding: 1em 2em;
+       right: 1em;
+       top: 7em;
+       width: 20em;
+       z-index: 10000;
+       border: solid 1px #a7d7f9;
+       border-radius: 0.75em;
+       -webkit-box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.125);
+       box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.125);
 }
 div#bodyContent {
        line-height: 1.5em;
index cc76b32..8b719e5 100644 (file)
@@ -1,21 +1,21 @@
-/*
+/**
  * Vector-specific scripts
  */
-jQuery( function( $ ) {
-       $( 'div.vectorMenu' ).each( function() {
-               var self = this;
-               $( 'h5:first a:first', this )
+jQuery( function ( $ ) {
+       $( 'div.vectorMenu' ).each( function () {
+               var $el = $( this );
+               $el.find( 'h5:first a:first' )
                        // For accessibility, show the menu when the hidden link in the menu is clicked (bug 24298)
-                       .click( function( e ) {
-                               $( '.menu:first', self ).toggleClass( 'menuForceShow' );
+                       .click( function ( e ) {
+                               $el.find( '.menu:first' ).toggleClass( 'menuForceShow' );
                                e.preventDefault();
-                       })
+                       } )
                        // When the hidden link has focus, also set a class that will change the arrow icon
-                       .focus( function() {
-                               $( self ).addClass( 'vectorMenuFocus' );
-                       })
-                       .blur( function() {
-                               $( self ).removeClass( 'vectorMenuFocus' );
-                       });
-       });
-});
+                       .focus( function () {
+                               $el.addClass( 'vectorMenuFocus' );
+                       } )
+                       .blur( function () {
+                               $el.removeClass( 'vectorMenuFocus' );
+                       } );
+       } );
+} );