/*______________ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K | / / | --------------------------------------------------- | / O / | MODULE : Uize.Widget.ImagePort.Draggable Class | / / / | | / / / /| | ONLINE : http://uize.com | /____/ /__/_| | COPYRIGHT : (c)2005-2016 UIZE | /___ | LICENSE : Available under MIT License or GNU General Public License |_______________| http://uize.com/license.html */ /* Module Meta Data type: Class importance: 3 codeCompleteness: 90 docCompleteness: 2 */ /*? Introduction The =Uize.Widget.ImagePort.Draggable= class extends its superclass by letting the user change logical sizing and positioning by clicking and dragging. *DEVELOPERS:* `Chris van Rensburg` */ Uize.module ({ name:'Uize.Widget.ImagePort.Draggable', required:'Uize.Widget.Drag', builder:function (_superclass) { 'use strict'; var /*** Variables for Scruncher Optimization ***/ _true = true, _false = false ; return _superclass.subclass ({ omegastructor:function () { var m = this; /*** add drag child widget ***/ var _drag = m.addChild ('drag',Uize.Widget.Drag,{idPrefixConstruction:'same as parent'}), _dragStartAlign = [], _dragStartSizingValue, _dragMode ; _drag.wire ({ 'Drag Start': function (_event) { _dragMode = _event.domEvent.ctrlKey ? 'sizing' : 'alignment'; m.set ({_inDrag:_true}); _dragStartSizingValue = m.get ('sizingValue'); _dragStartAlign [0] = m.get ('alignX'); _dragStartAlign [1] = m.get ('alignY'); }, 'Drag Update': function (_event) { if (_dragMode == 'sizing') { m.set ({ sizingValue:Uize.constrain ( _dragStartSizingValue + (0 - _drag.eventDeltaPos [1]) / 100, m._minSizingValue, m._maxSizingValue ) }); } else { var _calculateNewAlignValue = function (_axis) { return ( Uize.constrain ( _dragStartAlign [_axis] + _drag.eventDeltaPos [_axis] * ( m.portVsScaledDelta [_axis] ? (1 / m.portVsScaledDelta [_axis]) : 0 ), 0, 1 ) ); }; m.set ({ alignX:_calculateNewAlignValue (0), alignY:_calculateNewAlignValue (1) }); } }, 'Drag Done': function () {m.set ({_inDrag:_false})} }); /*** manage cursor state ***/ function _updateUiCursor () { var _alignApplicableX = m.get ('alignApplicableX'), _alignApplicableY = m.get ('alignApplicableY') ; m.children.drag.set ({ cursor: m._inZoomMode ? 'n-resize' : _alignApplicableX && _alignApplicableY ? 'move' : _alignApplicableX ? 'w-resize' : _alignApplicableY ? 'n-resize' : 'not-allowed' }); } m.wire ({ 'Changed.alignApplicableX':_updateUiCursor, 'Changed.alignApplicableY':_updateUiCursor, 'Changed.inZoomMode':_updateUiCursor }); }, instanceMethods:{ wireUi:function () { var m = this; if (!m.isWired) { /*** maintain inZoomMode state ***/ /* NOTE: - Unfortunately, must watch for ctrl pressed at document level (can't do it at the root node level). - There are issues with some browsers and how they reflect (or don't reflect) changes in the cursor style property of an element that the mouse is already over. - Safari seems to only reflect a cursor change on the next mousemove. - Opera seems to only reflect a cursor change on a more radical repaint / re-render (not sure exactly what it's logic is). - None of the browsers can pick up the key events if the document isn't focused (e.g. the location field is focused instead). */ m.wireNode ( document, { keydown:function (_event) {_event.ctrlKey && m.set ({_inZoomMode:_true})}, keyup:function () {m.set ({_inZoomMode:_false})} } ); _superclass.doMy (m,'wireUi'); } } }, stateProperties:{ _inDrag:{ name:'inDrag', value:_false }, _inZoomMode:{ name:'inZoomMode', value:_false }, _maxSizingValue:{ name:'maxSizingValue', value:Infinity }, _minSizingValue:{ name:'minSizingValue', value:0 } } }); } });