Disable inspection of references with unknown contents

Ed & Roan:
 Disable editing of references of which we are unable to find the
 source (e.g. <ref name="x"> without a target, or when the target is
 currently nested in something we don't yet process such as inside a
 <references> block or a template).

Timo:
 Improve UI to not be a regular focusable node where the inspector just
 won't show up but add a not-allowed cursor and explanatory tooltip.

James:
 Fix messages to refer to VisualEditor instead of "the" VisualEditor.

Change-Id: Ib2bca092ce13c9187fa8b27ad6a6404cae02aea2
This commit is contained in:
Ed Sanders 2013-06-13 09:30:13 +01:00 committed by Timo Tijhof
parent 9a8cb712b1
commit 9df1a59818
9 changed files with 86 additions and 36 deletions

View file

@ -13,7 +13,7 @@ $messages['en'] = array(
'tooltip-ca-editsource' => 'Edit the source code of this page',
'tooltip-ca-ve-edit' => 'Edit this page with VisualEditor',
'visualeditor' => 'VisualEditor',
'visualeditor-aliennode-tooltip' => 'Sorry, this element cannot be edited using the VisualEditor',
'visualeditor-aliennode-tooltip' => 'Sorry, this element cannot yet be edited using VisualEditor',
'visualeditor-annotationbutton-bold-tooltip' => 'Bold',
'visualeditor-annotationbutton-italic-tooltip' => 'Italic',
'visualeditor-annotationbutton-link-tooltip' => 'Link',
@ -48,7 +48,7 @@ $messages['en'] = array(
'visualeditor-dialog-meta-languages-code-label' => 'Language code',
'visualeditor-dialog-meta-languages-label' => 'Languages',
'visualeditor-dialog-meta-languages-link-label' => 'Linked page',
'visualeditor-dialog-meta-languages-readonlynote' => 'This is a list of pages in other languages that are linked to this one; it cannot yet be edited using the VisualEditor',
'visualeditor-dialog-meta-languages-readonlynote' => 'This is a list of pages in other languages that are linked to this one; it cannot yet be edited using VisualEditor',
'visualeditor-dialog-meta-languages-section' => 'Languages',
'visualeditor-dialog-meta-title' => 'Page settings',
'visualeditor-dialog-reference-content-section' => 'Reference content',
@ -122,6 +122,7 @@ $messages['en'] = array(
'visualeditor-outline-control-move-up' => 'Move item up',
'visualeditor-preference-enable' => 'Enable VisualEditor (only in the [[{{MediaWiki:Visualeditor-mainnamespacepagelink}}|main]] and [[{{MediaWiki:Visualeditor-usernamespacepagelink}}|user]] namespaces)',
'visualeditor-referencelist-isempty' => 'There are no references with the group "$1" on this page.',
'visualeditor-referencelist-missingref' => 'This reference is defined in a template or other generated block, and cannot yet be edited with VisualEditor.',
'visualeditor-reference-input-placeholder' => 'What do you want to reference?',
'visualeditor-reference-search-create' => 'Create new source',
'visualeditor-reference-search-reuse' => 'Use an existing source',
@ -173,14 +174,14 @@ See also:
* {{msg-mw|Tooltip-ca-createsource}} - used if the page doesn\'t exist',
'tooltip-ca-ve-edit' => 'Tooltip of the dedicated VisualEditor "Edit" tab.',
'visualeditor' => 'The name of the VisualEditor extension',
'visualeditor-aliennode-tooltip' => 'Tooltip for items that the VisualEditor cannot edit',
'visualeditor-aliennode-tooltip' => 'Tooltip for items that VisualEditor cannot edit',
'visualeditor-annotationbutton-bold-tooltip' => 'Tooltip text for bold button',
'visualeditor-annotationbutton-italic-tooltip' => 'Tooltip text for italic button',
'visualeditor-annotationbutton-link-tooltip' => 'Tooltip text for link button',
'visualeditor-beta-label' => 'Text of tool in the toolbar that highlights that VisualEditor is still in beta.
{{Identical|Beta}}',
'visualeditor-beta-warning' => "Note shown when user clicks on 'beta' label in VisualEditor, warning users that the software may have issues",
'visualeditor-browserwarning' => 'Edit notice shown when the VisualEditor loads, warning users that their browser is not officially supported',
'visualeditor-browserwarning' => 'Edit notice shown when VisualEditor loads, warning users that their browser is not officially supported',
'visualeditor-ca-createsource' => "Text for the create source link in the tab dropdown, if the page doesn't exist.
If the page exists, the following link text is used: {{msg-mw|Visualeditor-ca-editsource}}",
@ -193,7 +194,7 @@ Corresponds to the {{msg-mw|editsection}} message for default mode.',
'visualeditor-ca-ve-edit' => 'Link text of the dedicated VisualEditor "Edit" tab.',
'visualeditor-clearbutton-tooltip' => 'Tooltip text for the clear formatting button',
'visualeditor-desc' => '{{desc|name=VisualEditor|url=http://www.mediawiki.org/wiki/Extension:VisualEditor}}',
'visualeditor-descriptionpagelink' => 'Name of a page describing the use of the VisualEditor in this project.
'visualeditor-descriptionpagelink' => 'Name of a page describing the use of VisualEditor in this project.
{{doc-important|Do not translate "Project"; it is automatically converted to the wiki\'s project namespace.}}',
'visualeditor-dialog-action-apply' => 'Label text for button to apply changes made in dialog.
@ -345,7 +346,7 @@ Parameters:
'visualeditor-notification-saved' => 'Shown after a user saves a page, $1 is a page name.',
'visualeditor-outline-control-move-down' => 'Tool tip for a button that moves items in a list down one place',
'visualeditor-outline-control-move-up' => 'Tool tip for a button that moves items in a list up one place',
'visualeditor-preference-enable' => 'Label for the user preference to enable the VisualEditor.
'visualeditor-preference-enable' => 'Label for the user preference to enable VisualEditor.
Links are in {{msg-mw|Visualeditor-mainnamespacepagelink}} and {{msg-mw|visualeditor-usernamespacepagelink}}.',
'visualeditor-preference-nosectionedit' => 'Label for the user preference to make section edit links go to the old editor instead of VisualEditor.',
'visualeditor-reference-input-placeholder' => 'Placeholder text for reference search field.',

View file

@ -605,6 +605,7 @@ $wgResourceModules += array(
'visualeditor-outline-control-move-up',
'visualeditor-outline-control-move-up',
'visualeditor-referencelist-isempty',
'visualeditor-referencelist-missingref',
'visualeditor-reference-input-placeholder',
'visualeditor-reference-search-create',
'visualeditor-reference-search-reuse',

View file

@ -102,7 +102,7 @@ ve.ce.MWReferenceListNode.prototype.onListNodeUpdate = function () {
* Update the reference list.
*/
ve.ce.MWReferenceListNode.prototype.update = function () {
var i, j, iLen, jLen, index, firstNode, key, keyedNodes, $li, itemNode,
var i, j, iLen, jLen, index, firstNode, key, keyedNodes, $li, modelNode, viewNode,
internalList = this.model.getDocument().internalList,
refGroup = this.model.getAttribute( 'refGroup' ),
listGroup = this.model.getAttribute( 'listGroup' ),
@ -134,21 +134,29 @@ ve.ce.MWReferenceListNode.prototype.update = function () {
}
// Generate reference HTML from first item in key
itemNode = new ve.ce.InternalItemNode(
internalList.getItemNode( firstNode.getAttribute( 'listIndex' ) )
);
// HACK: PHP parser doesn't wrap single lines in a paragraph
if ( itemNode.$.children().length === 1 && itemNode.$.children( 'p' ).length === 1 ) {
// unwrap inner
itemNode.$.children().replaceWith( itemNode.$.children().contents() );
modelNode = internalList.getItemNode( firstNode.getAttribute( 'listIndex' ) );
if ( modelNode.length ) {
viewNode = new ve.ce.InternalItemNode( modelNode );
// HACK: PHP parser doesn't wrap single lines in a paragraph
if ( viewNode.$.children().length === 1 && viewNode.$.children( 'p' ).length === 1 ) {
// unwrap inner
viewNode.$.children().replaceWith( viewNode.$.children().contents() );
}
$li.append(
$( '<span>' )
.addClass( 'reference-text' )
.append( viewNode.$.clone().show() )
);
viewNode.destroy();
} else {
$li.append(
$( '<span>' )
.addClass( 've-ce-mwReferenceListNode-muted' )
.text( ve.msg( 'visualeditor-referencelist-missingref' ) )
);
}
$li.append(
$( '<span>' )
.addClass( 'reference-text' )
.append( itemNode.$.clone().show() )
);
this.$reflist.append( $li );
itemNode.destroy();
}
this.$.append( this.$reflist );
}

View file

@ -36,7 +36,6 @@ ve.ce.MWReferenceNode = function VeCeMWReferenceNode( model, config ) {
// Events
this.connect( this, { 'live': 'onLive' } );
this.$link.click( ve.bind( this.onClick, this ) );
// Initialization
this.update();
@ -96,18 +95,23 @@ ve.ce.MWReferenceNode.prototype.update = function () {
listGroup = this.model.getAttribute( 'listGroup' ),
refGroup = this.model.getAttribute( 'refGroup' ),
position = this.internalList.getIndexPosition( listGroup, listIndex );
this.$link.text( '[' + ( refGroup ? refGroup + ' ' : '' ) + ( position + 1 ) + ']' );
};
/**
* Handle the reference being clicked.
*
* @method
*/
ve.ce.MWReferenceNode.prototype.onClick = function ( e ) {
// TODO: Start editing. Internal item dm node can be accessed using:
// var itemNode = this.model.getInternalItem();
e.preventDefault();
ve.ce.MWReferenceNode.prototype.createPhantoms = function () {
// Parent method
ve.ce.ProtectedNode.prototype.createPhantoms.call( this );
if ( !this.getModel().isInspectable() ) {
// TODO: Move this into one of the classes mixin or inherit from
// as any focusable node that isn't inspectable should have this
// as it would be bad UX to have a focusable nodes where one of the
// same type doesn't show an inspector.
this.$phantoms
.addClass( 've-ce-mwReferenceNode-missingref' )
.attr( 'title', ve.msg( 'visualeditor-referencelist-missingref' ) );
}
};
/* Registration */

View file

@ -172,6 +172,12 @@
color: #777;
}
/* ve-ce-mwReferenceNode */
.ve-ce-mwReferenceNode-missingref {
cursor: not-allowed;
}
/* ve.ce.BranchNode */
.ve-ce-branchNode-blockSlug {

View file

@ -157,6 +157,16 @@ ve.dm.MWReferenceNode.static.remapInternalListIndexes = function ( dataElement,
/* Methods */
/**
* Don't allow reference nodes to be inspected if we can't find their contents.
*
* @inheritdoc
*/
ve.dm.MWReferenceNode.prototype.isInspectable = function () {
var internalItem = this.getInternalItem();
return internalItem && internalItem.getLength() > 0;
};
/**
* Gets the internal item node associated with this node
* @method

View file

@ -196,12 +196,16 @@ ve.dm.InternalList.prototype.convertToData = function ( converter ) {
list.push( { 'type': 'internalList' } );
for ( i = 0, length = itemHtmlQueue.length; i < length; i++ ) {
itemData = converter.getDataFromDomRecursion( $( '<div>' ).html( itemHtmlQueue[i] )[0] );
list = list.concat(
[{ 'type': 'internalItem' }],
itemData,
[{ 'type': '/internalItem' }]
);
if ( itemHtmlQueue[i] !== '' ) {
itemData = converter.getDataFromDomRecursion( $( '<div>' ).html( itemHtmlQueue[i] )[0] );
list = list.concat(
[{ 'type': 'internalItem' }],
itemData,
[{ 'type': '/internalItem' }]
);
} else {
list = list.concat( [ { 'type': 'internalItem' }, { 'type': '/internalItem' } ] );
}
}
list.push( { 'type': '/internalList' } );
// After conversion we no longer need the HTML

View file

@ -247,6 +247,18 @@ ve.dm.Node.static.isHybridInline = function ( domElements, converter ) {
/* Methods */
/**
* Check whether this node can be inspected by a tool.
*
* The default implementation always returns true. If your node type is uninspectable in certain
* cases, you should override this function.
*
* @returns {boolean} Whether this node is inspectable
*/
ve.dm.Node.prototype.isInspectable = function () {
return true;
};
/**
* Get a clone of the node's document data element.
*

View file

@ -82,6 +82,10 @@ ve.ui.ToolFactory.prototype.getToolsForAnnotations = function ( annotations ) {
ve.ui.ToolFactory.prototype.getToolForNode = function ( node ) {
var name, tool, candidateTool, candidateToolName;
if ( !node.isInspectable() ) {
return undefined;
}
for ( name in this.registry ) {
tool = this.registry[name];
if ( tool.static.canEditModel( node ) ) {