Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

New Resizer APIs: show, hide and toggle #1838

Merged
merged 3 commits into from
Oct 19, 2012
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 116 additions & 15 deletions src/utils/Resizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@
* while resizing), custom or internal resizes and save the final resized value into local
* storage for example.
*
* TODO Trigger panelResizeStart and panelResizeUpdate as required. They aren't needed
* currently.
* A resizable element can be collapsed/expanded using the `show`, `hide` and `toggle` APIs
*
* The resizable elements trigger a panelCollapsed and panelExpanded event when the panel toggles
* between visible and invisible
*/
define(function (require, exports, module) {
"use strict";
Expand All @@ -63,6 +65,41 @@ define(function (require, exports, module) {

var $mainView;

/**
* Shows a resizable element.
* @param {DOMNode} element Html element to show if possible
*/
function show(element) {
var showFunc = $(element).data("show");
if (showFunc) {
showFunc.apply(element);
}
}

/**
* Hides a resizable element.
* @param {DOMNode} element Html element to hide if possible
*/
function hide(element) {
var hideFunc = $(element).data("hide");
if (hideFunc) {
hideFunc.apply(element);
}
}

/**
* Changes the visibility state of a resizable element. The toggle
* functionality is added when an element is made resizable.
* @param {DOMNode} element Html element to toggle
*/
function toggle(element) {
if ($(element).is(":visible")) {
hide(element);
} else {
show(element);
}
}

/**
* Adds resizing capabilities to a given html element.
*
Expand All @@ -75,15 +112,21 @@ define(function (require, exports, module) {
* - Left ("left") or right ("right") for horizontal resizing
*
* A resizable element triggers the following events while resizing:
* - panelResizeStart: When the resize starts
* - panelResizeUpdate: When the resize gets updated
* - panelResizeEnds: When the resize ends
* - panelCollapsed: When the panel gets collapsed (or hidden)
* - panelExpanded: When the panel gets expanded (or shown)
*
* @param {DOMNode} element Html element which should be made resizable.
* @param {string} direction The direction of the resize action. Must be "horz" or "vert".
* @param {string} position The position of the resizer on the element. Can be "top" or "bottom"
* for vertical resizing and "left" or "right" for horizontal resizing.
* @param {int} minSize Minimum size (width or height) of the element.
* @param {boolean} collapsable True indicates the panel is collapsable on double click
* on the resizer.
*/
function makeResizable(element, direction, position, minSize) {
function makeResizable(element, direction, position, minSize, collapsable) {

var $resizer = $('<div class="' + direction + '-resizer"></div>'),
$element = $(element),
Expand All @@ -92,23 +135,52 @@ define(function (require, exports, module) {
animationRequest = null,
directionProperty = direction === DIRECTION_HORIZONTAL ? "clientX" : "clientY",
elementSizeFunction = direction === DIRECTION_HORIZONTAL ? $element.width : $element.height,
resizerCSSPosition = direction === DIRECTION_HORIZONTAL ? "left" : "top",
contentSizeFunction = null;

minSize = minSize || 0;
collapsable = collapsable || false;

$element.prepend($resizer);

$element.data("show", function () {
$element.show();

if (collapsable) {
$element.prepend($resizer);
$resizer.css(resizerCSSPosition, "");
}

EditorManager.resizeEditor();
$element.trigger("panelExpanded");
});

$element.data("hide", function () {
var elementOffset = $element.offset(),
elementSize = elementSizeFunction.apply($element);

$element.hide();
if (collapsable) {
$resizer.insertBefore($element).css(resizerCSSPosition, elementOffset[resizerCSSPosition] + elementSize);
}

EditorManager.resizeEditor();
$element.trigger("panelCollapsed");
});

$resizer.on("mousedown", function (e) {
var $resizeCont = $("<div class='resizing-container " + direction + "-resizing' />"),
startPosition = e[directionProperty],
startSize = elementSizeFunction.apply($element),
startSize = $element.is(":visible") ? elementSizeFunction.apply($element) : 0,
newSize = startSize,
baseSize = 0,
doResize = true,
doResize = false,
isMouseDown = true;

$body.append($resizeCont);


$element.trigger("panelResizeStart", [elementSizeFunction.apply($element)]);

if ($resizableElement !== undefined) {
$element.children().not(".horz-resizer, .vert-resizer, .resizable-content").each(function (index, child) {
if (direction === DIRECTION_HORIZONTAL) {
Expand All @@ -130,33 +202,59 @@ define(function (require, exports, module) {

if (doResize) {
// resize the main element to the new size
elementSizeFunction.apply($element, [newSize]);
if ($element.is(":visible")) {
elementSizeFunction.apply($element, [newSize]);

// if there is a content element, its size is the new size
// minus the size of the non-resizable elements
if ($resizableElement !== undefined) {
contentSizeFunction.apply($resizableElement, [newSize - baseSize]);
}

// if there is a content element, its size is the new size
// minus the size of the non-resizable elements
if ($resizableElement !== undefined) {
contentSizeFunction.apply($resizableElement, [newSize - baseSize]);
if (newSize < 10) {
toggle($element);
}
} else if (newSize > 10) {
elementSizeFunction.apply($element, [newSize]);
toggle($element);
$element.trigger("panelResizeStart", [elementSizeFunction.apply($element)]);
}

EditorManager.resizeEditor();
}

animationRequest = window.webkitRequestAnimationFrame(doRedraw);
});

$resizeCont.on("mousemove", function (e) {
doResize = true;
// calculate newSize adding to startSize the difference
// between starting and current position, capped at minSize
newSize = Math.max(startSize + (startPosition - e[directionProperty]), minSize);
$element.trigger("panelResizeUpdate", [newSize]);
e.preventDefault();
});

// If the element is marked as collapsable, check for double click
// to toggle the element visibility
if (collapsable) {
$resizeCont.on("mousedown", function (e) {
toggle($element);
});
}

function endResize(e) {
if (isMouseDown) {
isMouseDown = false;
$resizeCont.off("mousemove");
$resizeCont.remove();
$element.trigger("panelResizeEnd", [elementSizeFunction.apply($element)]);

// We wait 100ms to remove the resizer container to capture a mousedown
// on the container that would account for double click
window.setTimeout(function () {
$resizeCont.off("mousemove");
$resizeCont.off("mousedown");
$resizeCont.remove();
}, 100);
}
}

Expand All @@ -174,7 +272,7 @@ define(function (require, exports, module) {
$(".vert-resizable").each(function (index, element) {

if ($(element).hasClass("top-resizer")) {
makeResizable(element, DIRECTION_VERTICAL, POSITION_TOP, DEFAULT_MIN_SIZE);
makeResizable(element, DIRECTION_VERTICAL, POSITION_TOP, DEFAULT_MIN_SIZE, $(element).hasClass("collapsable"));
}

//if ($(element).hasClass("bottom-resizer")) {
Expand All @@ -195,4 +293,7 @@ define(function (require, exports, module) {
});

exports.makeResizable = makeResizable;
exports.toggle = toggle;
exports.show = show;
exports.hide = hide;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to have a setMinSize API so panels can have something different from the default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@redmunds Yes... I was planning to add it next, as it's required to finalize the sidebar refactor.

Panels using the makeResizable API can already set a minimum height. For the other ones, I was thinking of using a data-minSize attribute in the elements.

Would that be enough or do we still need an API to change the minSize at runtime? I would expect minSize to be set only during initialization...

Should I add it now, or wait to do it with the sidebar refactor final step?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think data-minSize is probably a better solution because it eliminates the timing of calling an API method to set it. It's ok to wait until the sidebar refactoring.

Also, I'm writing an extension that uses the bottom-panel with the resizer and I ran into the problem where I had to call makeResizable is not automatically called because extensions are not yet loaded when htmlReady() is called. I think this is fixed if you use appReady() instead. Let me know if you want me to send you a copy of the extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll be adding the data-minSize event in the next iteration, then.

About extensions, I also hit that same issue. I think scanning the DOM on appReady solves it in the case the extension adds the html to the DOM on htmlReady but not for any others.

@redmunds Please, send me a copy of your extension. I'd love to see it! I'll try to see if the Resizer module can be improved somehow to get a better workflow.