From f9a2c75b212df602ba72d0bc030e743f9c7f7ad0 Mon Sep 17 00:00:00 2001 From: Ed Sanders Date: Wed, 25 Sep 2013 12:25:44 +0100 Subject: [PATCH] Show a label with the current dimensions while resizing * Add config option to disable if required * Centre label within resize handles * Only show when resizing * Sexy opacity transitions, rounded corners and multiplication character Bug: 54297 Change-Id: Ic49430ce3302f780ae4b05d1fa29e14db1192c84 --- modules/ve/ce/styles/ve.ce.Node.css | 23 ++++++++++++ modules/ve/ce/ve.ce.ResizableNode.js | 56 ++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/modules/ve/ce/styles/ve.ce.Node.css b/modules/ve/ce/styles/ve.ce.Node.css index f7cb3d4f5c..929c7ca0f9 100644 --- a/modules/ve/ce/styles/ve.ce.Node.css +++ b/modules/ve/ce/styles/ve.ce.Node.css @@ -121,6 +121,29 @@ right: -0.33em; } +.ve-ce-resizableNode-sizeLabel { + position: absolute; + text-align: center; + opacity: 0; + -webkit-transition: opacity 200ms; + -moz-transition: opacity 200ms; + -o-transition: opacity 200ms; + transition: opacity 200ms; +} + +.ve-ce-resizableNode-sizeLabel-resizing { + opacity: 0.75; +} + +.ve-ce-resizableNode-sizeText { + font-size: 0.8em; + padding: 0.25em 0.5em; + border: solid 1px #ccc; + background-color: white; + border-radius: 0.3em; + white-space: nowrap; +} + /* ve.ce.RelocatableNode */ .ve-ce-relocatableNode-marker { diff --git a/modules/ve/ce/ve.ce.ResizableNode.js b/modules/ve/ce/ve.ce.ResizableNode.js index 882b45dffd..4878a2c18a 100644 --- a/modules/ve/ce/ve.ce.ResizableNode.js +++ b/modules/ve/ce/ve.ce.ResizableNode.js @@ -16,6 +16,7 @@ * @param {Object} [config] Configuration options * @param {number|null} [config.snapToGrid=10] Snap to a grid of size X when the shift key is held. Null disables. * @param {boolean} [config.outline=false] Resize using an outline of the element only, don't live preview. + * @param {boolean} [config.showSizeLabel=true] Show a label with the current dimensions while resizing */ ve.ce.ResizableNode = function VeCeResizableNode( $resizable, config ) { // Properties @@ -25,6 +26,10 @@ ve.ce.ResizableNode = function VeCeResizableNode( $resizable, config ) { this.$resizeHandles = this.$$( '
' ); this.snapToGrid = ( config && config.snapToGrid !== undefined ) ? config.snapToGrid : 10; this.outline = !!( config && config.outline ); + if ( !config || config.showSizeLabel !== false ) { + this.$sizeText = this.$$( '' ).addClass( 've-ce-resizableNode-sizeText' ); + this.$sizeLabel = this.$$( '
' ).addClass( 've-ce-resizableNode-sizeLabel' ).append( this.$sizeText ); + } // Events this.connect( this, { @@ -66,12 +71,57 @@ ve.ce.ResizableNode.static = {}; /* Methods */ +/** + * Update the contents and position of the size label + * + * Omitting the dimensions object will hide the size label. + * + * @param {Object} [dimensions] Dimensions object with width, height, top & left, or undefined to hide + */ +ve.ce.ResizableNode.prototype.updateSizeLabel = function ( dimensions ) { + if ( !this.$sizeLabel ) { + return; + } + var node, top, height; + if ( dimensions ) { + // Things get a bit tight below 100px, so put the label on the outside + if ( dimensions.width < 100 ) { + top = dimensions.top + dimensions.height; + height = 30; + } else { + top = dimensions.top; + height = dimensions.height; + } + this.$sizeLabel + .addClass( 've-ce-resizableNode-sizeLabel-resizing' ) + .css( { + 'top': top, + 'left': dimensions.left, + 'width': dimensions.width, + 'height': height, + 'lineHeight': height + 'px' + } ); + this.$sizeText.text( Math.round( dimensions.width ) + ' × ' + Math.round( dimensions.height ) ); + } else { + node = this; + // Defer the removal of this class otherwise other DOM changes may cause + // the opacity transition to not play out smoothly + setTimeout( function () { + node.$sizeLabel.removeClass( 've-ce-resizableNode-sizeLabel-resizing' ); + } ); + } +}; + /** * Handle node focus. * * @method */ ve.ce.ResizableNode.prototype.onResizableFocus = function () { + if ( this.$sizeLabel ) { + // Attach the size label first so it doesn't mask the resize handles + this.$sizeLabel.appendTo( this.root.getSurface().getSurface().$localOverlayControls ); + } this.$resizeHandles.appendTo( this.root.getSurface().getSurface().$localOverlayControls ); this.setResizableHandlesSizeAndPosition(); @@ -104,6 +154,9 @@ ve.ce.ResizableNode.prototype.onResizableFocus = function () { */ ve.ce.ResizableNode.prototype.onResizableBlur = function () { this.$resizeHandles.detach(); + if ( this.$sizeLabel ) { + this.$sizeLabel.detach(); + } }; /** @@ -136,6 +189,7 @@ ve.ce.ResizableNode.prototype.onResizableResizing = function ( dimensions ) { } ); this.setResizableHandlesPosition(); } + this.updateSizeLabel( dimensions ); }; /** @@ -174,6 +228,7 @@ ve.ce.ResizableNode.prototype.onResizeHandlesCornerMouseDown = function ( e ) { // Bind resize events this.resizing = true; + this.updateSizeLabel( this.resizeInfo ); $( this.getElementDocument() ).on( { 'mousemove.ve-ce-resizableNode': ve.bind( this.onDocumentMouseMove, this ), 'mouseup.ve-ce-resizableNode': ve.bind( this.onDocumentMouseUp, this ) @@ -335,6 +390,7 @@ ve.ce.ResizableNode.prototype.onDocumentMouseUp = function () { this.$resizeHandles.removeClass( 've-ce-resizableNode-handles-resizing' ); $( this.getElementDocument() ).off( '.ve-ce-resizableNode' ); this.resizing = false; + this.updateSizeLabel(); // Apply changes to the model attrChanges = this.getAttributeChanges( width, height );