jenkins-bot has submitted this change and it was merged.
Change subject: ve.ui.Context: Add embedding feature
......................................................................
ve.ui.Context: Add embedding feature
Objectives:
* Make the context menu display in the top right corner of the currently
focused inspectable node (if there is one)
* Prevent clicking on anything to do with the toolbar or popup from doing
anything at all, ever
Bonus:
* While we are using the clever feature in jQuery's on method which allows
passing boolean false to cancel the event - may as well do that in
ve.ui.Dialog as well
Changes:
ve.ui.FocusableNode
* Add ability to specify the focusable element so that dimensions can be
derived from it
ve.ce.Surface
* Add quotes to object keys
ve.ui.MediaDialog
* Change association from being MW specific to handling images in general
ve.ui.Context
* Add embedded styles for context
* Add embedded mode, which is triggered when the context is a single
focusable node, and the node is large enough to fit the context
reasonably
ve.ui.Dialog
* Inline mousedown handler
ve.ui.Toolbar, ve.ui.PopupWidget
* Cancel stray mousedown events
Change-Id: I4b25d33f64b4bcb8a3ecfd7e9728f54a2d4886f3
---
M modules/ve/ce/ve.ce.FocusableNode.js
M modules/ve/ce/ve.ce.Surface.js
M modules/ve/ui/dialogs/ve.ui.MediaDialog.js
M modules/ve/ui/styles/ve.ui.Context.css
M modules/ve/ui/ve.ui.Context.js
M modules/ve/ui/ve.ui.Dialog.js
M modules/ve/ui/ve.ui.Toolbar.js
M modules/ve/ui/widgets/ve.ui.PopupWidget.js
8 files changed, 71 insertions(+), 23 deletions(-)
Approvals:
Jforrester: Looks good to me, approved
jenkins-bot: Verified
diff --git a/modules/ve/ce/ve.ce.FocusableNode.js
b/modules/ve/ce/ve.ce.FocusableNode.js
index d3ebe49..8175be9 100644
--- a/modules/ve/ce/ve.ce.FocusableNode.js
+++ b/modules/ve/ce/ve.ce.FocusableNode.js
@@ -8,14 +8,23 @@
/**
* ContentEditable resizable node.
*
+ * Focusable elements have a special treatment by ve.ce.Surface. When the user
selects only a single
+ * node, if it is focusable, the surface will set the focusable node's focused
state. Other systems,
+ * such as the context, may also use a focusable node's $focusable property as
a hint of where the
+ * primary element in the node is. Typically, and by default, the primary
element is the root
+ * element, but in some cases it may need to be configured to be a specific
child element within the
+ * node's DOM rendering.
+ *
* @class
* @abstract
*
* @constructor
+ * @param {jQuery} [$focusable] Primary element user is focusing on
*/
-ve.ce.FocusableNode = function VeCeFocusableNode() {
+ve.ce.FocusableNode = function VeCeFocusableNode( $focusable ) {
// Properties
this.focused = false;
+ this.$focusable = $focusable || this.$;
};
/* Events */
diff --git a/modules/ve/ce/ve.ce.Surface.js b/modules/ve/ce/ve.ce.Surface.js
index 0f2f418..87b070f 100644
--- a/modules/ve/ce/ve.ce.Surface.js
+++ b/modules/ve/ce/ve.ce.Surface.js
@@ -177,8 +177,8 @@
};
} else {
return {
- start: sel.getStartDocumentPos(),
- end: sel.getEndDocumentPos()
+ 'start': sel.getStartDocumentPos(),
+ 'end': sel.getEndDocumentPos()
};
}
};
diff --git a/modules/ve/ui/dialogs/ve.ui.MediaDialog.js
b/modules/ve/ui/dialogs/ve.ui.MediaDialog.js
index 506a813..ed3983b 100644
--- a/modules/ve/ui/dialogs/ve.ui.MediaDialog.js
+++ b/modules/ve/ui/dialogs/ve.ui.MediaDialog.js
@@ -30,7 +30,9 @@
ve.ui.MediaDialog.static.icon = 'picture';
-ve.ui.MediaDialog.static.modelClasses = [ ve.dm.MWInlineImageNode ];
+ve.ui.MediaDialog.static.modelClasses = [ ve.dm.ImageNode ];
+
+/* Methods */
/* Registration */
diff --git a/modules/ve/ui/styles/ve.ui.Context.css
b/modules/ve/ui/styles/ve.ui.Context.css
index 7f2e0c1..096a844 100644
--- a/modules/ve/ui/styles/ve.ui.Context.css
+++ b/modules/ve/ui/styles/ve.ui.Context.css
@@ -35,3 +35,16 @@
.ve-ui-context-menu .ve-ui-buttonTool-active {
background-image: none;
}
+
+.ve-ui-context-embed .ve-ui-popupWidget-callout {
+ display: none;
+}
+
+.ve-ui-context-embed .ve-ui-popupWidget-body {
+ margin-top: 0.25em;
+ margin-left: -1.3em;
+}
+
+.ve-ui-context-embed .ve-ui-context-menu {
+ right: 0;
+}
diff --git a/modules/ve/ui/ve.ui.Context.js b/modules/ve/ui/ve.ui.Context.js
index 51f1940..68fad32 100644
--- a/modules/ve/ui/ve.ui.Context.js
+++ b/modules/ve/ui/ve.ui.Context.js
@@ -21,6 +21,7 @@
this.showing = false;
this.selecting = false;
this.relocating = false;
+ this.embedded = false;
this.selection = null;
this.toolbar = null;
this.$ = $( '<div>' );
@@ -53,6 +54,8 @@
'resize': ve.bind( this.update, this ),
'focus': ve.bind( this.onWindowFocus, this )
} );
+ this.$.add( this.$menu )
+ .on( 'mousedown', false );
};
/* Methods */
@@ -246,14 +249,25 @@
* @chainable
*/
ve.ui.Context.prototype.updateDimensions = function ( transition ) {
- var position, $container,
- inspector = this.inspectors.getCurrent();
+ var position, $container, focusableOffset, focusableWidth,
+ inspector = this.inspectors.getCurrent(),
+ focusedNode = this.surface.getView().getFocusedNode();
// Get cursor position
position = ve.ce.Surface.getSelectionRect();
- position = position && position.end;
+
if ( position ) {
- $container = inspector ? this.inspectors.$ : this.$menu;
+ if ( this.embedded ) {
+ focusableOffset = focusedNode.$focusable.offset();
+ focusableWidth = focusedNode.$focusable.outerWidth();
+ $container = this.$menu;
+ position = { 'x': focusableOffset.left +
focusableWidth, 'y': focusableOffset.top };
+ this.popup.align = 'right';
+ } else {
+ position = position && position.end;
+ $container = inspector ? this.inspectors.$ : this.$menu;
+ this.popup.align = 'center';
+ }
this.$.css( { 'left': position.x, 'top': position.y } );
this.popup.display(
position.x,
@@ -274,7 +288,8 @@
* @chainable
*/
ve.ui.Context.prototype.show = function ( transition ) {
- var inspector = this.inspectors.getCurrent();
+ var inspector = this.inspectors.getCurrent(),
+ focusedNode = this.surface.getView().getFocusedNode();
if ( !this.showing ) {
this.showing = true;
@@ -294,6 +309,16 @@
}, this ), 200 );
} else {
this.inspectors.$.hide();
+ if (
+ focusedNode &&
+ focusedNode.$focusable.outerHeight() >
this.$menu.outerHeight() * 2
+ ) {
+ this.$.addClass( 've-ui-context-embed' );
+ this.embedded = true;
+ } else {
+ this.$.removeClass( 've-ui-context-embed' );
+ this.embedded = false;
+ }
this.$menu.show();
}
diff --git a/modules/ve/ui/ve.ui.Dialog.js b/modules/ve/ui/ve.ui.Dialog.js
index d29fbe6..85d8feb 100644
--- a/modules/ve/ui/ve.ui.Dialog.js
+++ b/modules/ve/ui/ve.ui.Dialog.js
@@ -24,7 +24,7 @@
// Initialization
this.$.addClass( 've-ui-dialog' );
- this.$.on( 'mousedown', ve.bind( this.onMouseDown, this ) );
+ this.$.on( 'mousedown', false );
};
/* Inheritance */
@@ -32,16 +32,6 @@
ve.inheritClass( ve.ui.Dialog, ve.ui.Window );
/* Methods */
-
-/**
- * Handle mouse down events.
- *
- * @method
- * @param {jQuery.Event} e Mouse down event
- */
-ve.ui.Dialog.prototype.onMouseDown = function () {
- return false;
-};
/**
* Handle close button click events.
diff --git a/modules/ve/ui/ve.ui.Toolbar.js b/modules/ve/ui/ve.ui.Toolbar.js
index ac6f15f..f4b802e 100644
--- a/modules/ve/ui/ve.ui.Toolbar.js
+++ b/modules/ve/ui/ve.ui.Toolbar.js
@@ -32,6 +32,7 @@
this.surface = surface;
this.$bar = this.$$( '<div>' );
this.$tools = this.$$( '<div>' );
+ this.$actions = this.$$( '<div>' );
this.floating = false;
this.$window = null;
this.windowEvents = {
@@ -39,11 +40,15 @@
'scroll': ve.bind( this.onWindowScroll, this )
};
+ // Events
+ this.$
+ .add( this.$bar ).add( this.$tools ).add( this.$actions )
+ .on( 'mousedown', false );
+
// Initialization
this.$tools.addClass( 've-ui-toolbar-tools' );
this.$bar.addClass( 've-ui-toolbar-bar' ).append( this.$tools );
if ( options.actions ) {
- this.$actions = this.$$( '<div>' );
this.$actions.addClass( 've-ui-toolbar-actions' );
this.$bar.append( this.$actions );
}
@@ -160,6 +165,7 @@
group = tools[i];
// Create group
$group = this.$$( '<div class="ve-ui-toolbar-group"></div>' )
+ .on( 'mousedown', false )
.addClass( 've-ui-toolbar-group-' + group.name );
if ( group.label ) {
$group.append(
diff --git a/modules/ve/ui/widgets/ve.ui.PopupWidget.js
b/modules/ve/ui/widgets/ve.ui.PopupWidget.js
index 2db41a3..74f5d45 100644
--- a/modules/ve/ui/widgets/ve.ui.PopupWidget.js
+++ b/modules/ve/ui/widgets/ve.ui.PopupWidget.js
@@ -29,6 +29,11 @@
this.transitionTimeout = null;
this.align = config.align || 'center';
+ // Events
+ this.$body.on( 'blur', ve.bind( this.onPopupBlur, this ) );
+ this.$.add( this.$body ).add( this.$callout )
+ .on( 'mousedown', false );
+
// Initialization
this.$
.addClass( 've-ui-popupWidget' )
@@ -37,8 +42,6 @@
this.$body.addClass( 've-ui-popupWidget-body' )
);
- // Auto hide popup
- this.$body.on( 'blur', ve.bind( this.onPopupBlur, this ) );
};
/* Inheritance */
--
To view, visit https://gerrit.wikimedia.org/r/63243
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I4b25d33f64b4bcb8a3ecfd7e9728f54a2d4886f3
Gerrit-PatchSet: 10
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Robmoen <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: Trevor Parscal <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits