Mooeypoo has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/84014


Change subject: [WIP] StickeredNode mixin and StickerWidget
......................................................................

[WIP] StickeredNode mixin and StickerWidget

This is the UI piece of the StickerNode, a node mixin that allows for
static menus on block nodes for edit purposes. The widget will be
populated by inspectors for the node they are associated with.

The main use of this functionality is the Language Block node, but
the functionality will be useful for other block nodes like tables.

Change-Id: Iaef3afdf6ae8e18457146fbc03b6877494bcf650
---
M VisualEditor.php
A modules/ve/ce/ve.ce.StickeredNode.js
M modules/ve/ui/styles/ve.ui.Widget.css
A modules/ve/ui/ve.ui.Sticker.js
A modules/ve/ui/widgets/ve.ui.StickerWidget.js
5 files changed, 441 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor 
refs/changes/14/84014/1

diff --git a/VisualEditor.php b/VisualEditor.php
index 4920ed4..878ce47 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -705,6 +705,9 @@
                        've/ui/tools/ve.ui.BlockInspectorTool.js',
                        've/ui/actions/ve.ui.BlockInspectorAction.js',
                        've/ui/ve.ui.StickerToolbar.js',
+                       've/ce/ve.ce.StickeredNode.js',
+                       've/ui/ve.ui.Sticker.js',
+                       've/ui/widgets/ve.ui.StickerWidget.js',
                        've/ui/tools/ve.ui.ExperimentalTool.js',
                        've-mw/ui/tools/ve.ui.MWExperimentalTool.js',
                ),
diff --git a/modules/ve/ce/ve.ce.StickeredNode.js 
b/modules/ve/ce/ve.ce.StickeredNode.js
new file mode 100644
index 0000000..ecd7b9d
--- /dev/null
+++ b/modules/ve/ce/ve.ce.StickeredNode.js
@@ -0,0 +1,80 @@
+/*!
+ * VisualEditor ContentEditable FocusableNode class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * ContentEditable sticker node.
+ *
+ * Node that pops a sticky menu at the top.
+ *
+ * @param {jQuery} [$stickered=this.$] node jquery object
+ */
+ve.ce.StickeredNode = function VeCeStickeredNode( $stickered ) {
+       this.$stickered = $stickered || this.$;
+
+       this.$stickered.addClass( 've-ce-stickeredNode' );
+
+       this.$stickered.on( 'mouseenter', ve.bind( this.onMouseEnter, this ) );
+       this.$stickered.on( 'mouseleave', ve.bind( this.onMouseLeave, this ) );
+
+       this.dmNode = this.model; // <-- how do I get Dm of the current node??
+
+       this.surface = null;
+       this.sticker = null;
+
+       this.focused = false;
+       // Events
+       this.connect( this, {
+               'setup': 'onStickeredSetup',
+               'resize': 'onStickeredResize',
+               'rerender': 'onStickeredRerendered',
+       } );
+}
+
+ve.ce.StickeredNode.prototype.onStickeredSetup = function () {
+       this.surface = this.root.getSurface();
+       // Create Sticker:
+       this.sticker = new ve.ui.Sticker( this.surface.getSurface(), {
+               '$$': this.$$,
+               '$stickeredNode': this.$,
+               'nodeView': this,
+               'nodeModel': this.dmNode
+       } );
+       this.sticker.show( true );
+
+       // Repositioning Events:
+       this.surface.getModel()
+               .connect( this, { 'change': 'onStickeredModelChange' } );
+       this.surface.getSurface()
+               .connect( this, { 'position': 'onStickeredResize' } );
+
+}
+
+ve.ce.StickeredNode.prototype.onStickeredRerendered = function () {
+       this.updatePosition();
+}
+
+ve.ce.StickeredNode.prototype.onStickeredResize = function () {
+       this.updatePosition();
+
+}
+
+ve.ce.StickeredNode.prototype.onStickeredModelChange = function () {
+       this.updatePosition();
+       this.sticker.updateMenu();
+}
+
+ve.ce.StickeredNode.prototype.updatePosition = function() {
+       var $stickeredNode = this.$;
+       this.sticker.updateDimensions( true, $stickeredNode.position() );
+};
+
+ve.ce.StickeredNode.prototype.onMouseEnter = function () {
+       this.focused = true;
+};
+ve.ce.StickeredNode.prototype.onMouseLeave = function () {
+       this.focused = false;
+};
diff --git a/modules/ve/ui/styles/ve.ui.Widget.css 
b/modules/ve/ui/styles/ve.ui.Widget.css
index 2bf8ef3..aa002f9 100644
--- a/modules/ve/ui/styles/ve.ui.Widget.css
+++ b/modules/ve/ui/styles/ve.ui.Widget.css
@@ -575,3 +575,15 @@
        border-bottom-left-radius: 0;
        border-bottom-width: 0;
 }
+
+/* ve.ui.StickerWidget.js */
+
+.ve-ui-stickerWidget {
+       position: absolute;
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+       border: 1px solid #F2DCA0;
+       background: #FFFAC7;
+       padding: 2px;
+}
diff --git a/modules/ve/ui/ve.ui.Sticker.js b/modules/ve/ui/ve.ui.Sticker.js
new file mode 100644
index 0000000..80c3b7a
--- /dev/null
+++ b/modules/ve/ui/ve.ui.Sticker.js
@@ -0,0 +1,242 @@
+/*!
+ * VisualEditor UserInterface Context class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * UserInterface .
+ *
+ * @class
+ * @extends ve.Element
+ *
+ * @constructor
+ * @param {ve.ui.Surface} surface
+ * @param {Object} [config] Config options
+ */
+ve.ui.Sticker = function VeUiSticker( surface, config ) {
+       // Parent constructor
+       ve.Element.call( this, config );
+
+       // Properties
+       this.$stickeredNode = config.$stickeredNode;
+       this.nodeModel = config.nodeModel;
+       this.nodeView = config.nodeView;
+       this.surface = surface;
+       this.inspectors = {};
+       this.visible = false;
+       this.showing = false;
+       this.selecting = false;
+       this.relocating = false;
+       this.embedded = false;
+       this.selection = null;
+       this.toolbar = null;
+       this.popup = new ve.ui.StickerWidget( {
+               '$$': this.$$,
+               '$container': this.surface.$,
+               '$wrapper': this.$,
+               '$stickeredNode': this.$stickeredNode
+       } );
+       this.$menu = this.$$( '<div>' );
+       this.inspectors = new ve.ui.WindowSet( surface, ve.ui.inspectorFactory, 
{ 'isBlock': true } );
+
+       // Initialization
+       this.$.addClass( 've-ui-sticker' ).append( this.popup.$ );
+       this.inspectors.$.addClass( 've-ui-sticker-inspectors' );
+
+       this.popup.$body.append(
+               this.$menu.addClass( 've-ui-sticker-menu' ),
+               this.inspectors.$.addClass( 've-ui-sticker-inspectors' )
+       );
+
+       this.$.append( this.popup.$ );
+       this.surface.$localOverlay.append( this.$ );
+
+
+       // Events
+       this.inspectors.connect( this, {
+               'setup': 'onInspectorSetup',
+               'open': 'onInspectorOpen',
+               'close': 'onInspectorClose'
+       } );
+       this.$.add( this.$menu )
+               .on( 'mousedown', false );
+
+       this.$$( this.getElementWindow() ).on( {
+               'resize': ve.bind( this.updateMenu, this )
+       } );
+
+
+};
+
+
+/* Inheritance */
+
+ve.inheritClass( ve.ui.Sticker, ve.Element );
+
+/* Methods */
+
+/**
+ * Handle an inspector being setup.
+ *
+ * @method
+ * @param {ve.ui.Inspector} inspector Inspector that's been setup
+ */
+ve.ui.Sticker.prototype.onInspectorSetup = function () {
+//     this.selection = this.surface.getModel().getSelection();
+};
+
+/**
+ * Handle an inspector being opened.
+ *
+ * @method
+ * @param {ve.ui.Inspector} inspector Inspector that's been opened
+ */
+ve.ui.Sticker.prototype.onInspectorOpen = function () {
+       // Transition between menu and inspector
+       this.show( true );
+};
+
+/**
+ * Handle an inspector being closed.
+ *
+ * @method
+ * @param {ve.ui.Inspector} inspector Inspector that's been opened
+ * @param {boolean} accept Changes have been accepted
+ */
+ve.ui.Sticker.prototype.onInspectorClose = function () {
+//     this.updateDimensions();
+};
+
+/**
+ * Gets the surface the context is being used in.
+ *
+ * @method
+ * @returns {ve.ui.Surface} Surface of context
+ */
+ve.ui.Sticker.prototype.getSurface = function () {
+       return this.surface;
+};
+
+/**
+ * Destroy the context, removing all DOM elements.
+ *
+ * @method
+ * @returns {ve.ui.Context} Context UserInterface
+ * @chainable
+ */
+ve.ui.Sticker.prototype.destroy = function () {
+       this.$.remove();
+       return this;
+};
+
+/**
+ * Shows the context menu.
+ *
+ * @method
+ * @chainable
+ */
+ve.ui.Sticker.prototype.show = function ( transition ) {
+       var inspector = this.inspectors.getCurrent();
+       this.updateDimensions( true );
+       this.popup.show();
+       this.$.show();
+       this.visible = true;
+
+       return this;
+};
+
+/**
+ * Updates the context menu.
+ *
+ * @method
+ * @chainable
+ */
+ve.ui.Sticker.prototype.updateMenu = function () {
+       var i, nodes, tools,
+               inspector = this.inspectors.getCurrent(),
+               tool = ve.ui.toolFactory.getToolForNode( this.nodeModel );
+
+       // This is hard-coded for testing. until I figure out what's wrong with 
the getToolForNode()
+       tool = "languageblock";
+
+       // This should only take whatever the tool is for whatever stickerNode 
we're in
+       if ( tool ) {
+               // There's at least one inspectable annotation, build a menu 
and show it
+               this.$menu.empty();
+               if ( this.toolbar ) {
+                       this.toolbar.destroy();
+               }
+               this.toolbar = new ve.ui.StickerToolbar( this.surface, { 
'nodeView': this.nodeView, 'nodeModel': this.nodeModel } );
+               this.toolbar.setup( [ { 'include' : [ tool ] } ] );
+               this.$menu.append( this.toolbar.$ );
+               this.show();
+               this.toolbar.initialize();
+       } else if ( this.visible ) {
+               // Nothing to inspect (this shouldn't happen)
+               this.hide();
+       }
+
+       return this;
+};
+
+/**
+ * Updates the position and size of the sticker on top of the node.
+ *
+ * @method
+ * @chainable
+ */
+ve.ui.Sticker.prototype.updateDimensions = function ( transition, nodePosition 
) {
+       var $container, focusableOffset, focusableWidth,
+//             inspector = this.inspectors.getCurrent(),
+               position = nodePosition || this.$stickeredNode.position();
+
+               this.popup.display(
+                       position.left,
+                       position.top,
+                       200,
+                       35,
+                       transition
+               );
+
+
+       return this;
+};
+
+/**
+ * Hides the context menu.
+ *
+ * @method
+ * @chainable
+ */
+ve.ui.Sticker.prototype.hide = function () {
+       var inspector = this.inspectors.getCurrent();
+
+       if ( inspector ) {
+               // This will recurse, but inspector will be undefined next time
+               inspector.close( 'hide' );
+               return this;
+       }
+
+       this.popup.hide();
+       this.$.hide();
+       this.visible = false;
+
+       return this;
+};
+
+
+/**
+ * Opens a given inspector.
+ *
+ * @method
+ * @param {string} name Symbolic name of inspector
+ * @chainable
+ */
+ve.ui.Sticker.prototype.openInspector = function ( name ) {
+       if ( !this.inspectors.currentWindow ) {
+               this.inspectors.open( name );
+       }
+       return this;
+};
diff --git a/modules/ve/ui/widgets/ve.ui.StickerWidget.js 
b/modules/ve/ui/widgets/ve.ui.StickerWidget.js
new file mode 100644
index 0000000..e20a666
--- /dev/null
+++ b/modules/ve/ui/widgets/ve.ui.StickerWidget.js
@@ -0,0 +1,104 @@
+/*!
+ * VisualEditor UserInterface PopupWidget class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * Creates an ve.ui.StickerWidget object.
+ *
+ * @class
+ * @extends ve.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Config options
+ * @cfg {jQuery} [$container] Container to make sticker positioned relative to
+ */
+ve.ui.StickerWidget = function VeUiStickerWidget( config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       ve.ui.Widget.call( this, config );
+
+       // Properties
+       this.visible = false;
+       this.$body = this.$$( '<div>' );
+       this.transitionTimeout = null;
+       this.align = config.align || 'left';
+
+       this.$stickeredNode = config.$stickeredNode;
+       this.$wrapper = config.$wrapper || this.$;
+
+       // Events
+       this.$.add( this.$ )
+               .on( 'mousedown', function ( e ) {
+                       // Cancel only local mousedown events
+                       return e.target !== this;
+               } );
+
+       // Initialization
+       this.$.addClass( 've-ui-stickerWidget' );
+       this.$.append( this.$body );
+
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.ui.StickerWidget, ve.ui.Widget );
+
+
+/**
+ * Check if the sticker is visible.
+ *
+ * @method
+ * @returns {boolean} Popup is visible
+ */
+ve.ui.StickerWidget.prototype.isVisible = function () {
+       return this.visible;
+};
+
+/**
+ * Show the sticker.
+ *
+ * @method
+ * @chainable
+ */
+ve.ui.StickerWidget.prototype.show = function () {
+       this.$.show();
+       this.visible = true;
+       return this;
+};
+
+/**
+ * Show the sticker.
+ *
+ * @method
+ * @chainable
+ */
+ve.ui.StickerWidget.prototype.hide = function () {
+       this.$.hide();
+       this.visible = false;
+       this.emit( 'hide' );
+       return this;
+};
+
+
+/**
+ * Updates the position and size.
+ *
+ * @method
+ * @chainable
+ */
+ve.ui.StickerWidget.prototype.display = function ( x, y, width, height, 
transition ) {
+       this.$.css( {
+               'position': 'absolute',
+               'left': x,
+               'top': y - (height/2),
+               'width': width,
+               'height': height === undefined ? 'auto' : height
+       } );
+
+       return this;
+};

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iaef3afdf6ae8e18457146fbc03b6877494bcf650
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <mor...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to