(bug 43013) Exclude edit notices with no visible text.

en.wikipedia.org has a template gala for edit notices with a whole
bunch of html framework outputted by default from
MediaWiki:Editnotice-0 (even if their underlying system has no
matches for the current page).

In the core editor from EditPage.php this isn't a problem as the
element is just idling hidden above the editor.

In the case of VisualEditor (where we have a custom delivery for
the edit notices) we don't want to say "1 notice available" on
every page, so we need to be smart and quickly walk the dom of the
notice, filter out invisible nodes, and if the resulting nodes
have no contents, ignore the notice all together.

Change-Id: I65447da8b88a9bae9c24ff155544ff66b3fe9100
This commit is contained in:
Timo Tijhof 2012-12-13 01:22:10 +01:00
parent 3163cb4053
commit 18ab361a43
4 changed files with 90 additions and 7 deletions

View file

@ -67,6 +67,11 @@ $wgResourceModules += array(
'jquery/jquery.multiSuggest.js'
),
),
'jquery.visibleText' => $wgVisualEditorResourceTemplate + array(
'scripts' => array(
'jquery/jquery.visibleText.js'
),
),
// Alias for backwards compat, safe to remove after
'ext.visualEditor.editPageInit' => $wgVisualEditorResourceTemplate + array(
'dependencies' => array(
@ -113,6 +118,7 @@ $wgResourceModules += array(
'jquery.byteLimit',
'jquery.client',
'jquery.placeholder',
'jquery.visibleText',
'mediawiki.jqueryMsg',
'mediawiki.Title',
'mediawiki.Uri',

View file

@ -0,0 +1,46 @@
/**
* jQuery visibleText plugin 0.1.0
* https://github.com/Krinkle/jquery-visibleText
*
* @author Timo Tijhof, 2012
* @source This plugin is based on Sizzle.getText.
* Copyright 2012 jQuery Foundation and other contributors http://jquery.com/
* @license MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
(function ($) {
/**
* @param {Array|jQuery|HTMLElement} elem
*/
var getVisibleText = $.getVisibleText = function (elem) {
var node,
i = 0,
ret = '',
nodeType = elem.nodeType;
if (nodeType) {
if (nodeType === 1 || nodeType === 9 || nodeType === 11) {
// Traverse the children
for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
ret += $.expr.filters.hidden(elem) ?
'' :
getVisibleText(elem);
}
} else if (nodeType === 3 || nodeType === 4) {
return elem.nodeValue;
}
} else {
// If no nodeType, this is expected to be an array (or jQuery object)
for (; (node = elem[i]); i++) {
ret += getVisibleText(node);
}
}
return ret;
};
$.fn.visibleText = function () {
return getVisibleText(this);
};
}(jQuery));

View file

@ -646,11 +646,7 @@ ve.init.mw.ViewPageTarget.prototype.setupToolbarEditNotices = function () {
var key;
this.$toolbarEditNotices.empty();
for ( key in this.editNotices ) {
this.$toolbarEditNotices.append(
$( '<div>' )
.addClass( 've-init-mw-viewPageTarget-toolbar-editNotices-notice' )
.attr( 'rel', key ).html( this.editNotices[key] )
);
this.$toolbarEditNotices.append( this.editNotices[key] );
}
};

View file

@ -68,7 +68,9 @@ ve.inheritClass( ve.init.mw.Target, ve.EventEmitter );
* @emits loadError (null, message, null)
*/
ve.init.mw.Target.onLoad = function ( response ) {
var data = response.visualeditor;
var key, tmp, el,
data = response.visualeditor;
if ( !data && !response.error ) {
ve.init.mw.Target.onLoadError.call(
this, null, 'Invalid response in response from server', null
@ -81,7 +83,40 @@ ve.init.mw.Target.onLoad = function ( response ) {
);
} else {
this.dom = $( '<div>' ).html( data.content )[0];
this.editNotices = data.notices;
/**
* Don't show notices with no visible html (bug 43013).
*/
// Since we're going to parse them, we might as well save these nodes
// so we don't have to parse them again later.
this.editNotices = {};
// This is a temporary container for parsed notices in the <body>.
// We need the elements to be in the DOM in order for stylesheets to apply
// and jquery.visibleText to determine whether a node is visible.
tmp = document.createElement( 'div' );
// The following is essentially display none, but we can't use that
// since then then all descendants will be considered invisible too.
tmp.style.cssText = 'position: static; top: 0; width: 0; height: 0; border: 0; visibility: hidden';
document.body.appendChild( tmp );
for ( key in data.notices ) {
el = $( '<div>' )
.addClass( 've-init-mw-viewPageTarget-toolbar-editNotices-notice' )
.attr( 'rel', key )
.html( data.notices[key] )
.get( 0 );
tmp.appendChild( el );
if ( $.getVisibleText( el ).trim() !== '' ) {
this.editNotices[key] = el;
}
tmp.removeChild( el );
}
document.body.removeChild( tmp );
this.baseTimeStamp = data.basetimestamp;
this.startTimeStamp = data.starttimestamp;
// Everything worked, the page was loaded, continue as soon as the module is ready