jenkins-bot has submitted this change and it was merged.

Change subject: UI Refactor
......................................................................


UI Refactor

Changed:

VisualEditor.i18n.php
* Updated Link inspector i18n messages

ve.ui.MetaDialog.js -> ve.ui.PagedDialog
* Moved paging functionality into Paged dialog

ve.ui.EditorPanelLayout -> ve.ui.PagePanelLayout.js
* Renamed from EditorPanelLayout to work nicely with the concept of
  stacks and pages

ve.ui.GroupElement.js
* Added addItem method and change addItems to use it

ve.ui.Dialog.css
* Updated classname as per refactor of meta dialog

ve.ui.StackPanelLayout.js
* Set currentItem property on showItem
* In addItems method, show currentItem with class method
** rather display block on element

ve.ui.Layout.css
* Make editorPanel layout 100% in width.

ve.ui.Widget.css
* Added CategoryWidget and CategoryPopup styles
* Other adjustments

ve.ui.PopupWidget.js
* Added auto-close on loss of focus
* Made friendly with being initialized inside a frame

ve.ui.MWLinkTargetInputWidget.js
* Mixin ve.ui.PendingInputWidget and remove pending methods
* Prevent querying on spaces
* Reintroduce i18n messages for menu sections

ve.ui.MenuWidget.js
* Update cases of $input config property to input

New:

ve.ui.PagedDialog.js
* Refactored base-class for mwMeta dialog (and probably other dialogs
  too)
* Abstracts adding and accessing pages

ve.ui.PendingInputWidget.js
* Moved pushPending and popPending methods into pending class

Change-Id: I29bcd92b7b5641941a4e98e65b2a56424a5263ff
---
M VisualEditor.i18n.php
M VisualEditor.php
M demos/ve/index.php
M modules/ve/test/index.php
D modules/ve/ui/dialogs/ve.ui.MetaDialog.js
A modules/ve/ui/dialogs/ve.ui.PagedDialog.js
M modules/ve/ui/elements/ve.ui.GroupElement.js
R modules/ve/ui/layouts/panels/ve.ui.PagePanelLayout.js
M modules/ve/ui/layouts/panels/ve.ui.StackPanelLayout.js
M modules/ve/ui/styles/ve.ui.Dialog.css
M modules/ve/ui/styles/ve.ui.Layout.css
M modules/ve/ui/styles/ve.ui.Widget.css
M modules/ve/ui/widgets/ve.ui.MWLinkTargetInputWidget.js
M modules/ve/ui/widgets/ve.ui.MenuWidget.js
A modules/ve/ui/widgets/ve.ui.PendingInputWidget.js
M modules/ve/ui/widgets/ve.ui.PopupWidget.js
16 files changed, 252 insertions(+), 154 deletions(-)

Approvals:
  Robmoen: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/VisualEditor.i18n.php b/VisualEditor.i18n.php
index 81ad233..e762ada 100644
--- a/VisualEditor.i18n.php
+++ b/VisualEditor.i18n.php
@@ -43,9 +43,9 @@
        'visualeditor-feedback-tool' => 'Leave feedback',
        'visualeditor-window-title' => 'Inspect',
        'visualeditor-linkinspector-title' => 'Hyperlink',
-       'visualeditor-linkinspector-suggest-existing-page' => 'Existing page',
+       'visualeditor-linkinspector-suggest-matching-page' => 'Matching page',
        'visualeditor-linkinspector-suggest-new-page' => 'New page',
-       'visualeditor-linkinspector-suggest-external-link' => 'Web link',
+       'visualeditor-linkinspector-suggest-external-link' => 'External link',
        'visualeditor-formatdropdown-title' => 'Change format',
        'visualeditor-formatdropdown-format-paragraph' => 'Paragraph',
        'visualeditor-formatdropdown-format-heading1' => 'Heading 1',
@@ -154,7 +154,7 @@
        'visualeditor-window-title' => 'Title of an unnamed inspector',
        'visualeditor-linkinspector-title' => 'Title of the link inspector 
dialog.
 {{Identical|Hyperlink}}',
-       'visualeditor-linkinspector-suggest-existing-page' => 'Label for 
suggested existing pages in the link inspector',
+       'visualeditor-linkinspector-suggest-matching-page' => 'Label for 
suggested matching local wiki pages in the link inspector',
        'visualeditor-linkinspector-suggest-new-page' => 'Label for a new page 
in the link inspector',
        'visualeditor-linkinspector-suggest-external-link' => 'Label for an 
external (Web) link in the link inspector',
        'visualeditor-formatdropdown-title' => 'This is a tooltip for the 
drop-down box for choosing the formatting style of the selected text, such as 
"Heading 1", "Heading 2" or "Plain text". (This is not related to "file format" 
or "data format", such as "Wikitext", "HTML", "PDF" etc.)',
diff --git a/VisualEditor.php b/VisualEditor.php
index 4591a0e..c7a5896 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -373,6 +373,7 @@
                        've/ui/widgets/ve.ui.MenuItemWidget.js',
                        've/ui/widgets/ve.ui.MenuSectionItemWidget.js',
                        've/ui/widgets/ve.ui.MenuWidget.js',
+                       've/ui/widgets/ve.ui.PendingInputWidget.js',
                        've/ui/widgets/ve.ui.TextInputMenuWidget.js',
                        've/ui/widgets/ve.ui.LinkTargetInputWidget.js',
                        've/ui/widgets/ve.ui.MWLinkTargetInputWidget.js',
@@ -380,11 +381,11 @@
                        've/ui/layouts/ve.ui.GridLayout.js',
                        've/ui/layouts/ve.ui.PanelLayout.js',
                        've/ui/layouts/panels/ve.ui.StackPanelLayout.js',
-                       've/ui/layouts/panels/ve.ui.EditorPanelLayout.js',
+                       've/ui/layouts/panels/ve.ui.PagePanelLayout.js',
 
                        've/ui/dialogs/ve.ui.ContentDialog.js',
                        've/ui/dialogs/ve.ui.MediaDialog.js',
-                       've/ui/dialogs/ve.ui.MetaDialog.js',
+                       've/ui/dialogs/ve.ui.PagedDialog.js',
 
                        've/ui/tools/ve.ui.ButtonTool.js',
                        've/ui/tools/ve.ui.AnnotationButtonTool.js',
@@ -445,7 +446,8 @@
                        'visualeditor',
                        'visualeditor-inspector-title',
                        'visualeditor-linkinspector-title',
-                       'visualeditor-linkinspector-suggest-existing-page',
+                       'visualeditor-linkinspector-label-pagetitle',
+                       'visualeditor-linkinspector-suggest-matching-page',
                        'visualeditor-linkinspector-suggest-new-page',
                        'visualeditor-linkinspector-suggest-external-link',
                        'visualeditor-formatdropdown-title',
diff --git a/demos/ve/index.php b/demos/ve/index.php
index 712a94b..d072c49 100644
--- a/demos/ve/index.php
+++ b/demos/ve/index.php
@@ -254,16 +254,17 @@
                <script 
src="../../modules/ve/ui/widgets/ve.ui.MenuItemWidget.js"></script>
                <script 
src="../../modules/ve/ui/widgets/ve.ui.MenuSectionItemWidget.js"></script>
                <script 
src="../../modules/ve/ui/widgets/ve.ui.MenuWidget.js"></script>
+               <script 
src="../../modules/ve/ui/widgets/ve.ui.PendingInputWidget.js"></script>
                <script 
src="../../modules/ve/ui/widgets/ve.ui.TextInputMenuWidget.js"></script>
                <script 
src="../../modules/ve/ui/widgets/ve.ui.LinkTargetInputWidget.js"></script>
                <script 
src="../../modules/ve/ui/widgets/ve.ui.MWLinkTargetInputWidget.js"></script>
                <script 
src="../../modules/ve/ui/layouts/ve.ui.GridLayout.js"></script>
                <script 
src="../../modules/ve/ui/layouts/ve.ui.PanelLayout.js"></script>
                <script 
src="../../modules/ve/ui/layouts/panels/ve.ui.StackPanelLayout.js"></script>
-               <script 
src="../../modules/ve/ui/layouts/panels/ve.ui.EditorPanelLayout.js"></script>
+               <script 
src="../../modules/ve/ui/layouts/panels/ve.ui.PagePanelLayout.js"></script>
                <script 
src="../../modules/ve/ui/dialogs/ve.ui.ContentDialog.js"></script>
                <script 
src="../../modules/ve/ui/dialogs/ve.ui.MediaDialog.js"></script>
-               <script 
src="../../modules/ve/ui/dialogs/ve.ui.MetaDialog.js"></script>
+               <script 
src="../../modules/ve/ui/dialogs/ve.ui.PagedDialog.js"></script>
                <script 
src="../../modules/ve/ui/tools/ve.ui.ButtonTool.js"></script>
                <script 
src="../../modules/ve/ui/tools/ve.ui.AnnotationButtonTool.js"></script>
                <script 
src="../../modules/ve/ui/tools/ve.ui.DialogButtonTool.js"></script>
diff --git a/modules/ve/test/index.php b/modules/ve/test/index.php
index 84eb40b..df34fe5 100644
--- a/modules/ve/test/index.php
+++ b/modules/ve/test/index.php
@@ -197,16 +197,17 @@
                <script 
src="../../ve/ui/widgets/ve.ui.MenuItemWidget.js"></script>
                <script 
src="../../ve/ui/widgets/ve.ui.MenuSectionItemWidget.js"></script>
                <script src="../../ve/ui/widgets/ve.ui.MenuWidget.js"></script>
+               <script 
src="../../ve/ui/widgets/ve.ui.PendingInputWidget.js"></script>
                <script 
src="../../ve/ui/widgets/ve.ui.TextInputMenuWidget.js"></script>
                <script 
src="../../ve/ui/widgets/ve.ui.LinkTargetInputWidget.js"></script>
                <script 
src="../../ve/ui/widgets/ve.ui.MWLinkTargetInputWidget.js"></script>
                <script src="../../ve/ui/layouts/ve.ui.GridLayout.js"></script>
                <script src="../../ve/ui/layouts/ve.ui.PanelLayout.js"></script>
                <script 
src="../../ve/ui/layouts/panels/ve.ui.StackPanelLayout.js"></script>
-               <script 
src="../../ve/ui/layouts/panels/ve.ui.EditorPanelLayout.js"></script>
+               <script 
src="../../ve/ui/layouts/panels/ve.ui.PagePanelLayout.js"></script>
                <script 
src="../../ve/ui/dialogs/ve.ui.ContentDialog.js"></script>
                <script src="../../ve/ui/dialogs/ve.ui.MediaDialog.js"></script>
-               <script src="../../ve/ui/dialogs/ve.ui.MetaDialog.js"></script>
+               <script src="../../ve/ui/dialogs/ve.ui.PagedDialog.js"></script>
                <script src="../../ve/ui/tools/ve.ui.ButtonTool.js"></script>
                <script 
src="../../ve/ui/tools/ve.ui.AnnotationButtonTool.js"></script>
                <script 
src="../../ve/ui/tools/ve.ui.DialogButtonTool.js"></script>
diff --git a/modules/ve/ui/dialogs/ve.ui.MetaDialog.js 
b/modules/ve/ui/dialogs/ve.ui.MetaDialog.js
deleted file mode 100644
index 1751ce3..0000000
--- a/modules/ve/ui/dialogs/ve.ui.MetaDialog.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/*!
- * VisualEditor user interface MetaDialog class.
- *
- * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
- * @license The MIT License (MIT); see LICENSE.txt
- */
-
-/**
- * Document dialog.
- *
- * @class
- * @abstract
- * @extends ve.ui.Dialog
- *
- * @constructor
- * @param {ve.Surface} surface
- */
-ve.ui.MetaDialog = function VeUiMetaDialog( surface ) {
-       // Parent constructor
-       ve.ui.Dialog.call( this, surface );
-};
-
-/* Inheritance */
-
-ve.inheritClass( ve.ui.MetaDialog, ve.ui.Dialog );
-
-/* Static Properties */
-
-ve.ui.MetaDialog.static.titleMessage = 'visualeditor-dialog-meta-title';
-
-ve.ui.MetaDialog.static.icon = 'settings';
-
-/* Methods */
-
-/**
- * Handle frame ready events.
- *
- * @method
- */
-ve.ui.MetaDialog.prototype.initialize = function () {
-       // Call parent method
-       ve.ui.Dialog.prototype.initialize.call( this );
-
-       // Properties
-       this.outlinePanel = new ve.ui.PanelLayout( { '$$': this.$$, 'scroll': 
true } );
-       this.editorPanel = new ve.ui.StackPanelLayout( { '$$': this.$$ } );
-       this.editorPanels = {
-               'categories': new ve.ui.EditorPanelLayout( {
-                       '$$': this.$$, 'icon': 'tag', 'label': 'Categories'
-               } ),
-               'languages': new ve.ui.EditorPanelLayout( {
-                       '$$': this.$$, 'icon': 'language', 'label': 'Languages'
-               } )
-       };
-       this.layout = new ve.ui.GridLayout(
-               [this.outlinePanel, this.editorPanel],
-               { '$$': this.$$, 'widths': [1, 2] }
-       );
-       this.editorPanel.addItems( ve.getObjectValues( this.editorPanels ) );
-
-       // HACK
-       this.outlineWidget = new ve.ui.OutlineWidget( { '$$': this.$$ } );
-       this.outlineWidget.addItems( [
-               new ve.ui.OutlineItemWidget(
-                       'categories', { '$$': this.$$, 'icon': 'tag', 'label': 
'Categories' }
-               ),
-               new ve.ui.OutlineItemWidget(
-                       'languages', { '$$': this.$$, 'icon': 'language', 
'label': 'Languages' }
-               )
-       ] );
-       this.outlineWidget
-               .on( 'select', ve.bind( function ( item ) {
-                       this.editorPanel.showItem( 
this.editorPanels[item.getData()] );
-               }, this ) )
-               .selectItem( this.outlineWidget.getClosestSelectableItem( 0 ) );
-
-       // Initialization
-       this.outlinePanel.$.addClass( 've-ui-metaDialog-outlinePanel' );
-       this.editorPanel.$.addClass( 've-ui-metaDialog-editorPanel' );
-       this.$body.append( this.layout.$ );
-       this.outlinePanel.$.append( this.outlineWidget.$ );
-       this.layout.update();
-};
-
-/* Registration */
-
-ve.ui.dialogFactory.register( 'meta', ve.ui.MetaDialog );
diff --git a/modules/ve/ui/dialogs/ve.ui.PagedDialog.js 
b/modules/ve/ui/dialogs/ve.ui.PagedDialog.js
new file mode 100644
index 0000000..f9a1c12
--- /dev/null
+++ b/modules/ve/ui/dialogs/ve.ui.PagedDialog.js
@@ -0,0 +1,100 @@
+/*!
+ * VisualEditor user interface PagedDialog class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * Paged dialog.
+ *
+ * A paged dialog has an outline in the left third, and a series of pages in 
the right two-thirds.
+ * Pages can be added using the #addPage method, and later accessed using 
`this.pages[name]` or
+ * through the #getPage method.
+ *
+ * @class
+ * @abstract
+ * @extends ve.ui.Dialog
+ *
+ * @constructor
+ * @param {ve.Surface} surface
+ */
+ve.ui.PagedDialog = function VeUiPagedDialog( surface ) {
+       // Parent constructor
+       ve.ui.Dialog.call( this, surface );
+
+       // Properties
+       this.pages = {};
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.ui.PagedDialog, ve.ui.Dialog );
+
+/* Methods */
+
+/**
+ * Handle frame ready events.
+ *
+ * @method
+ */
+ve.ui.PagedDialog.prototype.initialize = function () {
+       // Call parent method
+       ve.ui.Dialog.prototype.initialize.call( this );
+
+       // Properties
+       this.outlinePanel = new ve.ui.PanelLayout( { '$$': this.$$, 'scroll': 
true } );
+       this.pagesPanel = new ve.ui.StackPanelLayout( { '$$': this.$$ } );
+       this.layout = new ve.ui.GridLayout(
+               [this.outlinePanel, this.pagesPanel], { '$$': this.$$, 
'widths': [1, 2] }
+       );
+       this.outlineWidget = new ve.ui.OutlineWidget( { '$$': this.$$ } );
+
+       // Events
+       this.outlineWidget.on( 'select', ve.bind( function ( item ) {
+               if ( item ) {
+                       this.pagesPanel.showItem( this.pages[item.getData()] );
+               }
+       }, this ) );
+
+       // Initialization
+       this.outlinePanel.$.append( this.outlineWidget.$ ).addClass( 
've-ui-pagedDialog-outlinePanel' );
+       this.pagesPanel.$.addClass( 've-ui-pagedDialog-pagesPanel' );
+       this.$body.append( this.layout.$ );
+};
+
+/**
+ * Add a page to the dialog.
+ *
+ * @method
+ * @param {string} name Symbolic name of page
+ * @param {jQuery|string} [label] Page label
+ * @param {string} [icon] Symbolic name of icon
+ * @chainable
+ */
+ve.ui.PagedDialog.prototype.addPage = function ( name, label, icon ) {
+       var config = { '$$': this.$$, 'icon': icon, 'label': label || name };
+
+       // Create and add page panel and outline item
+       this.pages[name] = new ve.ui.PagePanelLayout( config );
+       this.pagesPanel.addItems( [this.pages[name]] );
+       this.outlineWidget.addItems( [ new ve.ui.OutlineItemWidget( name, 
config ) ] );
+
+       // Auto-select first item when nothing is selected yet
+       if ( !this.outlineWidget.getSelectedItem() ) {
+               this.outlineWidget.selectItem( 
this.outlineWidget.getClosestSelectableItem( 0 ) );
+       }
+
+       return this;
+};
+
+/**
+ * Get a page by name.
+ *
+ * @method
+ * @param {string} name Symbolic name of page
+ * @returns {ve.ui.PagePanelLayout|undefined} Page, if found
+ */
+ve.ui.PagedDialog.prototype.getPage = function ( name ) {
+       return this.pages[name];
+};
diff --git a/modules/ve/ui/elements/ve.ui.GroupElement.js 
b/modules/ve/ui/elements/ve.ui.GroupElement.js
index 904a7f7..eec22df 100644
--- a/modules/ve/ui/elements/ve.ui.GroupElement.js
+++ b/modules/ve/ui/elements/ve.ui.GroupElement.js
@@ -41,20 +41,29 @@
  * @chainable
  */
 ve.ui.GroupElement.prototype.addItems = function ( items ) {
-       var i, len, item;
-
+       var i, len;
        for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-
-               // Check if item exists then remove it first, effectively 
"moving" it
-               if ( this.items.indexOf( item ) !== -1 ) {
-                       this.removeItems( [item] );
-               }
-               // Add the item
-               this.items.push( item );
-               this.$group.append( item.$ );
-               this.$items = this.$items.add( item.$ );
+               this.addItem( items[i] );
        }
+       return this;
+};
+
+/**
+ * Add item.
+ *
+ * @method
+ * @param {ve.ui.Widget} item Item
+ * @chainable
+ */
+ve.ui.GroupElement.prototype.addItem = function ( item ) {
+       // Check if item exists then remove it first, effectively "moving" it
+       if ( this.items.indexOf( item ) !== -1 ) {
+               this.removeItems( [item] );
+       }
+       // Add the item
+       this.items.push( item );
+       this.$.append( item.$ );
+       this.$items = this.$items.add( item.$ );
 
        return this;
 };
@@ -70,7 +79,6 @@
  */
 ve.ui.GroupElement.prototype.removeItems = function ( items ) {
        var i, len, item, index;
-
        // Remove specific items
        for ( i = 0, len = items.length; i < len; i++ ) {
                item = items[i];
diff --git a/modules/ve/ui/layouts/panels/ve.ui.EditorPanelLayout.js 
b/modules/ve/ui/layouts/panels/ve.ui.PagePanelLayout.js
similarity index 64%
rename from modules/ve/ui/layouts/panels/ve.ui.EditorPanelLayout.js
rename to modules/ve/ui/layouts/panels/ve.ui.PagePanelLayout.js
index 59cd3f7..c783b59 100644
--- a/modules/ve/ui/layouts/panels/ve.ui.EditorPanelLayout.js
+++ b/modules/ve/ui/layouts/panels/ve.ui.PagePanelLayout.js
@@ -1,12 +1,12 @@
 /*!
- * VisualEditor UserInterface EditorPanelLayout class.
+ * VisualEditor UserInterface PagePanelLayout class.
  *
  * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
  * @license The MIT License (MIT); see LICENSE.txt
  */
 
 /**
- * Editor panel layout.
+ * Page panel layout.
  *
  * @class
  * @extends ve.ui.PanelLayout
@@ -16,7 +16,7 @@
  * @param {Object} [config] Config options
  * @cfg {string} [icon=''] Symbolic icon name
  */
-ve.ui.EditorPanelLayout = function VeUiEditorPanelLayout( config ) {
+ve.ui.PagePanelLayout = function VeUiPagePanelLayout( config ) {
        // Config initialization
        config = ve.extendObject( config, { 'scroll': true } );
 
@@ -26,6 +26,9 @@
        // Mixin constructors
        ve.ui.LabeledElement.call( this, this.$$( '<div>' ), config );
 
+       // Properties
+       this.icon = config.icon;
+
        // Initialization
        this.$label.addClass( 've-ui-icon-' + config.icon + '-big' );
        this.$.append( this.$label ).addClass( 've-ui-editorPanelLayout' );
@@ -33,6 +36,12 @@
 
 /* Inheritance */
 
-ve.inheritClass( ve.ui.EditorPanelLayout, ve.ui.PanelLayout );
+ve.inheritClass( ve.ui.PagePanelLayout, ve.ui.PanelLayout );
 
-ve.mixinClass( ve.ui.EditorPanelLayout, ve.ui.LabeledElement );
+ve.mixinClass( ve.ui.PagePanelLayout, ve.ui.LabeledElement );
+
+/* Methods */
+
+ve.ui.PagePanelLayout.prototype.getIcon = function () {
+       return this.icon;
+};
diff --git a/modules/ve/ui/layouts/panels/ve.ui.StackPanelLayout.js 
b/modules/ve/ui/layouts/panels/ve.ui.StackPanelLayout.js
index 51e432e..5bf34ac 100644
--- a/modules/ve/ui/layouts/panels/ve.ui.StackPanelLayout.js
+++ b/modules/ve/ui/layouts/panels/ve.ui.StackPanelLayout.js
@@ -55,7 +55,7 @@
 
        for ( i = 0, len = items.length; i < len; i++ ) {
                if ( !this.currentItem ) {
-                       items[i].$.show();
+                       this.showItem( items[i] );
                } else {
                        items[i].$.hide();
                }
@@ -113,6 +113,7 @@
 ve.ui.StackPanelLayout.prototype.showItem = function ( item ) {
        this.$items.hide();
        item.$.show();
+       this.currentItem = item;
 
        return this;
 };
diff --git a/modules/ve/ui/styles/ve.ui.Dialog.css 
b/modules/ve/ui/styles/ve.ui.Dialog.css
index 4ed959c..26eea26 100644
--- a/modules/ve/ui/styles/ve.ui.Dialog.css
+++ b/modules/ve/ui/styles/ve.ui.Dialog.css
@@ -117,6 +117,6 @@
        margin: 0.25em 0.25em;
 }
 
-.ve-ui-metaDialog-outlinePanel {
+.ve-ui-pagedDialog-outlinePanel {
        border-right: solid 1px #ddd;
 }
diff --git a/modules/ve/ui/styles/ve.ui.Layout.css 
b/modules/ve/ui/styles/ve.ui.Layout.css
index a7ca079..8e647c1 100644
--- a/modules/ve/ui/styles/ve.ui.Layout.css
+++ b/modules/ve/ui/styles/ve.ui.Layout.css
@@ -25,6 +25,7 @@
 
 .ve-ui-editorPanelLayout {
        padding: 1.5em;
+       width: 100%;
        -webkit-box-sizing:border-box;
        -moz-box-sizing:border-box;
        box-sizing:border-box;
diff --git a/modules/ve/ui/styles/ve.ui.Widget.css 
b/modules/ve/ui/styles/ve.ui.Widget.css
index 562b01c..3ea4ca8 100644
--- a/modules/ve/ui/styles/ve.ui.Widget.css
+++ b/modules/ve/ui/styles/ve.ui.Widget.css
@@ -236,9 +236,8 @@
 
 .ve-ui-menuWidget {
        position: absolute;
-       background: #FFFFFF;
+       background: #fff;
        margin-top: -1px;
-       font-size: 0.8em;
        z-index: 101;
        border: solid 1px #ccc;
        border-radius: 0 0 0.25em 0.25em;
@@ -268,9 +267,9 @@
        cursor: default;
 }
 
-/* ve.ui.MWLinkTargetInputWidget */
+/* ve.ui.PendingInputWidget */
 
-.ve-ui-mwLinkTargetInputWidget-pending input {
+.ve-ui-pendingInputWidget input {
        background-image: url(images/pending.gif);
 }
 
@@ -279,6 +278,7 @@
 .ve-ui-mwLinkTargetInputWidget-menu {
        width: 20em;
        margin-top: -7px;
+       font-size: 0.8em;
 }
 
 .ve-ui-mwLinkTargetInputWidget-menu .ve-ui-menuWidget-item {
@@ -331,3 +331,9 @@
        -o-transition-timing-function: ease-in-out;
        transition-timing-function: ease-in-out;
 }
+
+.ve-ui-popupWidget-body:focus {
+       /* No outline. The body has a tabindex and is focused on show */
+       outline: none;
+}
+
diff --git a/modules/ve/ui/widgets/ve.ui.MWLinkTargetInputWidget.js 
b/modules/ve/ui/widgets/ve.ui.MWLinkTargetInputWidget.js
index c8c77e6..b404f7e 100644
--- a/modules/ve/ui/widgets/ve.ui.MWLinkTargetInputWidget.js
+++ b/modules/ve/ui/widgets/ve.ui.MWLinkTargetInputWidget.js
@@ -56,6 +56,8 @@
 
 ve.inheritClass( ve.ui.MWLinkTargetInputWidget, ve.ui.LinkTargetInputWidget );
 
+ve.mixinClass( ve.ui.MWLinkTargetInputWidget, ve.ui.PendingInputWidget );
+
 /* Methods */
 
 /**
@@ -138,7 +140,7 @@
        this.populateMenu();
        this.queryPageExistence();
        this.queryMatchingPages();
-       if ( this.value.length && !this.menu.isVisible() ) {
+       if ( this.value.length && $.trim( this.value ) !== '' && 
!this.menu.isVisible() ) {
                this.menu.show();
        }
        return this;
@@ -169,7 +171,7 @@
        // External link
        if ( ve.init.platform.getExternalLinkUrlProtocolsRegExp().test( 
this.value ) ) {
                items.push( new ve.ui.MenuSectionItemWidget(
-                       'externalLink', { '$$': menu$$, 'label': 'External 
link' }
+                       'externalLink', { '$$': menu$$, 'label': ve.msg( 
'visualeditor-linkinspector-suggest-external-link' ) }
                ) );
                items.push( new ve.ui.MenuItemWidget(
                        this.getExternalLinkAnnotationFromUrl( this.value ),
@@ -180,7 +182,7 @@
        // Internal link
        if ( !pageExists && ( !matchingPages || matchingPages.indexOf( 
this.value ) === -1 ) ) {
                items.push( new ve.ui.MenuSectionItemWidget(
-                       'newPage', { '$$': menu$$, 'label': 'New page' }
+                       'newPage', { '$$': menu$$, 'label': ve.msg( 
'visualeditor-linkinspector-suggest-new-page' ) }
                ) );
                items.push( new ve.ui.MenuItemWidget(
                        this.getInternalLinkAnnotationFromTitle( this.value ),
@@ -191,7 +193,7 @@
        // Matching pages
        if ( matchingPages && matchingPages.length ) {
                items.push( new ve.ui.MenuSectionItemWidget(
-                       'matchingPages', { '$$': menu$$, 'label': 'Matching 
page' }
+                       'matchingPages', { '$$': menu$$, 'label': ve.msg( 
'visualeditor-linkinspector-suggest-matching-page' ) }
                ) );
                for ( i = 0, len = matchingPages.length; i < len; i++ ) {
                        items.push( new ve.ui.MenuItemWidget(
@@ -212,30 +214,6 @@
        }
        this.menu.highlightItem( this.menu.getSelectedItem() );
 
-       return this;
-};
-
-/**
- * Signals that an response is pending.
- *
- * @method
- * @chainable
- */
-ve.ui.MWLinkTargetInputWidget.prototype.pushPending = function () {
-       this.pending++;
-       this.$.addClass( 've-ui-mwLinkTargetInputWidget-pending' );
-       return this;
-};
-
-/**
- * Signals that an response is complete.
- *
- * @method
- * @chainable
- */
-ve.ui.MWLinkTargetInputWidget.prototype.popPending = function () {
-       this.pending--;
-       this.$.removeClass( 've-ui-mwLinkTargetInputWidget-pending' );
        return this;
 };
 
diff --git a/modules/ve/ui/widgets/ve.ui.MenuWidget.js 
b/modules/ve/ui/widgets/ve.ui.MenuWidget.js
index 91175bb..2be85d7 100644
--- a/modules/ve/ui/widgets/ve.ui.MenuWidget.js
+++ b/modules/ve/ui/widgets/ve.ui.MenuWidget.js
@@ -34,7 +34,7 @@
 
        // Initialization
        this.$.hide().addClass( 've-ui-menuWidget' );
-       if ( !config.$input ) {
+       if ( !config.input ) {
                this.$.append( this.$input );
        }
 };
diff --git a/modules/ve/ui/widgets/ve.ui.PendingInputWidget.js 
b/modules/ve/ui/widgets/ve.ui.PendingInputWidget.js
new file mode 100644
index 0000000..7a47626
--- /dev/null
+++ b/modules/ve/ui/widgets/ve.ui.PendingInputWidget.js
@@ -0,0 +1,38 @@
+/*!
+ * VisualEditor UserInterface PendingInputWidget class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * Creates an ve.ui.PendingInputWidget object.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ */
+ve.ui.PendingInputWidget = function VeUiPendingInputWidget () {
+       this.pending = 0;
+};
+
+/* Methods */
+
+/**
+ * Adds a pending marker
+ */
+ve.ui.PendingInputWidget.prototype.pushPending = function () {
+       this.pending++;
+       this.$.addClass( 've-ui-pendingInputWidget' );
+       return this;
+};
+
+/**
+ * Removes a pending marker
+ */
+ve.ui.PendingInputWidget.prototype.popPending = function () {
+       this.pending--;
+       this.$.removeClass( 've-ui-pendingInputWidget' );
+       return this;
+};
diff --git a/modules/ve/ui/widgets/ve.ui.PopupWidget.js 
b/modules/ve/ui/widgets/ve.ui.PopupWidget.js
index 56c0bee..2db41a3 100644
--- a/modules/ve/ui/widgets/ve.ui.PopupWidget.js
+++ b/modules/ve/ui/widgets/ve.ui.PopupWidget.js
@@ -23,8 +23,9 @@
 
        // Properties
        this.visible = false;
-       this.$callout = $( '<div>' );
-       this.$body = $( '<div>' );
+       this.$callout = this.$$( '<div>' );
+       // Tab index on body so that it may blur
+       this.$body = this.$$( '<div>' ).attr( 'tabindex', 1 );
        this.transitionTimeout = null;
        this.align = config.align || 'center';
 
@@ -35,11 +36,20 @@
                        this.$callout.addClass( 've-ui-popupWidget-callout' ),
                        this.$body.addClass( 've-ui-popupWidget-body' )
                );
+
+       // Auto hide popup
+       this.$body.on( 'blur', ve.bind( this.onPopupBlur, this ) );
 };
 
 /* Inheritance */
 
 ve.inheritClass( ve.ui.PopupWidget, ve.ui.Widget );
+
+/* Events */
+
+/**
+ * @event hide
+ */
 
 /* Methods */
 
@@ -52,7 +62,8 @@
 ve.ui.PopupWidget.prototype.show = function () {
        this.$.show();
        this.visible = true;
-
+       // Focus body so that it may blur.
+       this.$body.focus();
        return this;
 };
 
@@ -65,10 +76,39 @@
 ve.ui.PopupWidget.prototype.hide = function () {
        this.$.hide();
        this.visible = false;
-
+       this.emit( 'hide' );
        return this;
 };
 
+ve.ui.PopupWidget.prototype.getFocusedChild = function () {
+       return this.$body.find( ':focus' );
+};
+
+ve.ui.PopupWidget.prototype.onPopupBlur = function () {
+       // Find out what is focused after blur
+       setTimeout( ve.bind( function () {
+               var $focused = this.getFocusedChild();
+               // Is there a focused child element?
+               if ( $focused.length > 0 ) {
+                       // Bind a one off blur event to that focused child 
element
+                       $focused.one( 'blur', ve.bind( function () {
+                               setTimeout( ve.bind( function () {
+                                       if ( this.getFocusedChild().length === 
0 ) {
+                                               // Be sure focus is not the 
popup itself.
+                                               if ( this.$.find( ':focus' 
).is( this.$body ) ){
+                                                       return;
+                                               }
+                                               // Not a child and not the 
popup itself, so hide.
+                                               this.hide();
+                                       }
+                               }, this ), 0 );
+                       }, this ) );
+               } else {
+                       this.hide();
+               }
+       }, this ), 0 );
+};
+
 /**
  * Updates the position and size.
  *

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I29bcd92b7b5641941a4e98e65b2a56424a5263ff
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Trevor Parscal <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: Robmoen <[email protected]>
Gerrit-Reviewer: Siebrand <[email protected]>
Gerrit-Reviewer: jenkins-bot

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

Reply via email to