c9-core/plugins/c9.ide.ui/lib/splitbox.js

1568 wiersze
58 KiB
JavaScript

define(function(require, module, exports) {
return function(apf) {
var $setTimeout = setTimeout;
var $setInterval = setInterval;
/**
* This abstraction is using for resizing block elements. Resizing is allowed
* with square elements in vertical, horizontal or both planes. Symmetric
* resizing is possible with SHIFT button.
*
* @private
* @default_private
* @constructor
*
* @author Lukasz Lipinski
* @version %I%, %G%
* @since 1.0
*
*/
apf.resize = function() {
/**
* {Boolean} scalex resizing in horizontal plane, default is true
* Possible values:
* true resizing in horizontal plane is allowed
* false resizing in horizontal plane is not allowed
* {Boolean} scaley resizing in vertical plane, default is true
* Possible values:
* true resizing in vertical plane is allowed
* false resizing in vertical plane is not allowed
* {Boolean} scaleratio resizing in horizontal or vertical plane only is not allowed. Resizing in two dimensions plane at the same time is allowed.
* Possible values:
* true resizing in two dimensions plane at the same time is allowed
* false Resizing in two dimensions plane at the same time is not allowed
* {Number} dwidth the minimal horizontal size of Block element, default is 56 pixels
* {Number} dheight the minimal vertical size of Block element, default is 56 pixels
*/
this.scales = {
scalex: false,
scaley: false,
scaleratio: false,
dwidth: 0,
dheight: 0,
snap: false,
gridW: 48,
gridH: 48
};
/*
* html representation of resized block element
*/
this.htmlElement;
/**
* store object representations of inputs elements
*/
var squares = [];
this.init = function() {
squares = [
new apf.resize.square("top", "left", this),
new apf.resize.square("top", "middle", this),
new apf.resize.square("top", "right", this),
new apf.resize.square("middle", "left", this),
new apf.resize.square("middle", "right", this),
new apf.resize.square("bottom", "left", this),
new apf.resize.square("bottom", "middle", this),
new apf.resize.square("bottom", "right", this)];
};
/**
* Links block element with resize feature
*
* @param {HTMLElement} oHtml html representation of block element
* @param {Object} scales blocks scale settings
*/
this.grab = function(oHtml, scales) {
this.htmlElement = oHtml;
this.scales = scales;
if (!squares.length)
this.init();
this.show();
};
/**
* Hides all block squares
*/
this.hide = function() {
for (var i = 0, l = squares.length; i < l; i++) {
squares[i].visible = false;
squares[i].repaint();
}
};
/**
* Shows all block squares
*/
this.show = function() {
var sx = this.scales.scalex;
var sy = this.scales.scaley;
var sr = this.scales.scaleratio;
for (var i = 0, l = squares.length, s; i < l; i++) {
s = squares[i];
s.visible = sx && sy
? true
: (sy && !sx
? (s.posX == "middle"
? true
: false)
: (sx && !sy
? (s.posY == "middle"
? true
: false)
: (sr
? ((s.posY == "top" || s.posY == "bottom")
&& s.posX !== "middle"
? true
: false)
: false)));
s.repaint();
}
};
/**
* Destroys all block squares
*/
this.destroy = function(){
for (var i = 0; i < squares.length; i++) {
squares[i].destroy();
}
};
};
/*
* Creates html and object representation for square element. Square is used for
* resizing block elements.
*
* @param {String} posY square vertical align relative to resized block element
* Possible values:
* top square is on top of resized block element
* middle square is in the middle of the resized block element
* bottom square is on the bottom of resized block element
* @param {String} posX square vertical align relative to resized block element
* Possible values:
* left square is on the left of resized block element
* middle square is in the middle of the resized block element
* right square is on the right of resized block element
* @param {Object} objResize object of resize class
* @constructor
*/
apf.resize.square = function(posY, posX, objResize) {
/*
* Square visibility
*/
this.visible = true;
/*
* square vertical align relative to resized block element
*/
this.posX = posX;
/*
* square vertical align relative to resized block element
*/
this.posY = posY;
var margin = 0;
var _self = this;
/*
* html represenation of square element
*/
this.htmlElement = objResize.htmlElement.parentNode.appendChild(document.createElement('div'));
apf.setStyleClass(this.htmlElement, "square");
/*
* Repaints square
*/
this.repaint = function() {
if (this.visible) {
var block = objResize.htmlElement;
this.htmlElement.style.display = "block";
var bw = parseInt(block.style.width) + apf.getDiff(block)[0];
var bh = parseInt(block.style.height) + apf.getDiff(block)[1];
var bt = parseInt(block.style.top);
var bl = parseInt(block.style.left);
var sw = this.htmlElement.offsetWidth;
var sh = this.htmlElement.offsetHeight;
var t = posY == "top"
? bt - margin - sh
: posY == "middle"
? bt + bh/2 - sh/2
: bt + bh + margin;
var l = posX == "left"
? bl - margin - sw
: posX == "middle"
? bl + bw/2 - sw/2
: bl + bw + margin;
var c = (posY == "middle"
? "w-resize"
: (posX == "middle"
? "n-resize"
: (posY + posX == "topleft"
|| posY + posX == "bottomright")
? "nw-resize"
: "ne-resize"));
this.htmlElement.style.top = (t - 1) + "px";
this.htmlElement.style.left = (l - 1) + "px";
this.htmlElement.style.cursor = c;
}
else {
//IE bug
var sw = this.htmlElement.offsetWidth;
this.htmlElement.style.display = 'none';
}
};
this.destroy = function(){
apf.destroyHtmlNode(this.htmlElement);
};
/* Events */
this.htmlElement.onmouseover = function(e) {
apf.setStyleClass(_self.htmlElement, "squareHover");
};
this.htmlElement.onmouseout = function(e) {
apf.setStyleClass(_self.htmlElement, "", ["squareHover"]);
};
this.htmlElement.onmousedown = function(e) {
e = (e || event);
var block = objResize.htmlElement,
sx = e.clientX,
sy = e.clientY,
pt = block.parentNode.offsetTop,
pl = block.parentNode.offsetLeft,
dw = objResize.scales.dwidth,
dh = objResize.scales.dheight,
snap = objResize.scales.snap,
gridH = objResize.scales.gridH,
gridW = objResize.scales.gridW,
objBlock = apf.flow.isBlock(block),
r = objBlock.other.ratio,
posX = _self.posX,
posY = _self.posY,
width, height, top, left, dx, dy,
prev_w, prev_h,
l = parseInt(block.style.left),
t = parseInt(block.style.top),
w = parseInt(block.style.width),
h = parseInt(block.style.height),
resized = false;
objResize.onresizedone(w, h, t, l);
if (e.preventDefault) {
e.preventDefault();
}
document.onmousemove = function(e) {
e = (e || event);
dx = e.clientX - sx;
dy = e.clientY - sy;
var shiftKey = e.shiftKey,
proportion = r;
if (shiftKey) {
if (posX == "right" && posY == "bottom") {
width = w + dx;
height = width/proportion;
left = l;
top = t;
}
else if (posX == "right" && posY == "top") {
width = w + dx;
height = width/proportion;
left = l;
top = t - dx/proportion;
}
else if (posX == "left" && posY == "bottom") {
width = w - dx;
height = width/proportion;
left = l + dx;
top = t;
}
else if (posX == "left" && posY == "top") {
width = w - dx;
height = width/proportion;
left = l + dx;
top = t + dx/proportion;
}
/* Keep minimal size */
if (width >= dw && height >= dh) {
width = prev_w = Math.max(dw, width);
height = prev_h = Math.max(dh, height);
}
else {
width = prev_w;
height = prev_h;
return false;
}
}
else {
width = posX == "right"
? w + dx
: (posX == "left"
? w - dx
: w);
height = posY == "bottom"
? h + dy
: (posY == "top"
? h - dy
: h);
left = posX == "right"
? l
: (posX == "left"
? Math.min(l + w - dw, l + dx)
: l);
top = posY == "bottom"
? t
: (posY == "top"
? Math.min(t + h - dh, t + dy)
: t);
/* Keep minimal size */
width = Math.max(dw, width);
height = Math.max(dh, height);
}
if (snap) {
left = Math.floor(left / gridW) * gridW;
top = Math.floor(top / gridH) * gridH;
width = Math.ceil(width / gridW) * gridW;
height = Math.ceil(height / gridH) * gridH;
}
if (objResize.onresize) {
objResize.onresize(block, top, left, width, height);
}
objResize.show();
resized = true;
};
document.onmouseup = function(e) {
document.onmousemove = null;
if (objResize.onresizedone && resized) {
objResize.onresizedone(width, height, top, left);
objBlock.other.ratio = width / height;
resized = false;
}
};
};
};
/**
*
* A container that stacks two children vertically.
*
* Programatically, this is identical to a regular [[vbox]], except that it can
* only accept two children, and uses absolute positioning. Because of this, there
* is more work required to construct AML that matches a regular `<a:vbox>`; however,
* the performance improvements in using a `<a:vsplitbox>` are massive.
*
* @class apf.vsplitbox
* @define vsplitbox
* @layout
*
* @inheritDoc apf.hsplitbox
*
* @author Ruben Daniels (ruben AT ajax DOT org)
* @version %I%, %G%
* @since 3.0
* @see element.hsplitbox
*/
/**
*
* A container that stacks two children horizontally.
*
* Programatically, this is identical to a regular [[apf.hbox]], except that it can
* only accept two children, and uses absolute positioning. Because of this, there
* is more work required to construct AML that matches a regular `<a:hbox>`; however,
* the performance improvements in using a `<a:hsplitbox>` are massive.
*
* @class apf.hsplitbox
* @define hsplitbox
* @layout
* @inherits apf.GuiElement
*
* @author Ruben Daniels (ruben AT ajax DOT org)
* @version %I%, %G%
* @since 3.0\
* @see element.vsplitbox
*/
apf.hsplitbox = function(struct, tagName) {
this.$init(tagName || "hsplitbox", apf.NODE_VISIBLE, struct);
};
apf.vsplitbox = function(struct, tagName) {
this.$init(tagName || "vsplitbox", apf.NODE_VISIBLE, struct);
};
(function(){
this.minwidth = 0;
this.minheight = 0;
this.padding = 0;
this.edge = 0;
this.$edge = [0,0,0,0];
// *** Properties and Attributes *** //
this.$focussable = false;
this.$useLateDom = true;
this.$box = true;
this.$layout = true;
/**
* @attribute {String} [padding="2"] Sets or gets the space between each element.
*/
/**
* @attribute {String} [edge="5 5 5 5"] Sets or gets the space between the container and the elements, space seperated in pixels for each side. Similar to CSS in the sequence of `top right bottom left`.
*/
this.$booleanProperties["splitter"] = true;
this.$supportedProperties.push("padding", "edge", "splitter");
this.$propHandlers["padding"] = function(value) {
this.padding = parseInt(value);
if (!this.$amlLoaded)
return;
if (this.$handle)
this.$handle.$ext.style[this.$vbox ? "height" : "width"] = value + "px";
var firstChild = this.getFirstChild();
var lastChild = this.getSecondChild();
if (this.$vbox) {
//Two flex children
if (this.flexChild2) {
if (firstChild.height) {
// This is not needed because with bottom: xx% it already works
// if (String(firstChild.height).indexOf("%") == -1) {
lastChild.$ext.style.marginTop = firstChild.visible
? value + "px" // + apf.getHeightDiff(firstChild.$ext)
: 0;
// }
}
else {
firstChild.$ext.style.marginBottom = lastChild.visible
? (value
+ apf.getHeightDiff(lastChild.$ext)) + "px"
: 0;
}
}
else if (this.fixedChild && this.fixedChild.visible) {
//One flex child (first)
if (this.flexChild1 == firstChild) {
if (this.fixedChild.visible) {
this.flexChild1.$ext.style.bottom =
(parseInt(this.fixedChild.height) + value + this.$edge[2]) + "px";
}
}
//One flex child (last)
else if (lastChild && this.flexChild1 == lastChild) {
this.flexChild1.$ext.style.top =
(parseInt(this.fixedChild.height) + value + this.$edge[2]) + "px";
}
}
}
else {
//Two flex children
if (this.flexChild2) {
if (firstChild.width) {
lastChild.$ext.style.marginLeft =
(value
+ apf.getWidthDiff(firstChild.$ext)
+ apf.getMargin(firstChild.$ext)[0]) + "px";
}
else {
firstChild.$ext.style.marginRight =
(value + (lastChild
? apf.getWidthDiff(lastChild.$ext)
+ apf.getMargin(lastChild.$ext)[0]
: 0)) + "px";
}
}
else if (this.fixedChild && this.fixedChild.visible) {
//One flex child (first)
if (this.flexChild1 == firstChild) {
this.flexChild1.$ext.style.right =
(parseInt(this.fixedChild.width) + value + this.$edge[1]) + "px";
}
//One flex child (last)
else if (lastChild && this.flexChild1 == lastChild) {
this.flexChild1.$ext.style.left =
(parseInt(this.fixedChild.width) + value + this.$edge[3]) + "px";
}
}
}
}
this.$propHandlers["splitter"] = function(value) {
if (value) {
if (this.$handle)
this.$handle.show();
else {
this.$handle = this.insertBefore(
this.ownerDocument.createElementNS(apf.ns.aml, "splitter"),
this.lastChild);
}
}
else {
this.$handle && this.$handle.hide();//destroy(true, true);
}
}
this.$propHandlers["edge"] = function(value, setSize) {
this.$edge = apf.getBox(value);
if (!this.$amlLoaded)
return;
var fNode = this.getFirstVisibleChild();
if (!fNode) {
this.hide();
return false;
}
fNode.$ext.style.left = (this.$edge[3] + fNode.$margin[3]) + "px";
fNode.$ext.style.top = (this.$edge[0] + fNode.$margin[0]) + "px";
if (this.$vbox)
fNode.$ext.style.right = (this.$edge[1] + fNode.$margin[1]) + "px";
else
fNode.$ext.style.bottom = (this.$edge[2] + fNode.$margin[2]) + "px";
var lNode = this.getSecondVisibleChild();
if (lNode && lNode.visible && lNode.$ext) {
lNode.$ext.style.right = (this.$edge[1] + lNode.$margin[1]) + "px";
lNode.$ext.style.bottom = (this.$edge[2] + lNode.$margin[2]) + "px";
if (this.$vbox) {
var isPercentage;
lNode.$ext.style.left = (this.$edge[3] + lNode.$margin[3]) + "px";
if (fNode.height || fNode.height === 0) {
isPercentage = String(fNode.height).indexOf("%") > -1;
lNode.$ext.style.top = isPercentage
? fNode.height
: ((parseInt(fNode.height) + this.padding
+ this.$edge[0] + fNode.$margin[0]) + "px");
if (isPercentage) {
fNode.$ext.style.height = "";
fNode.$ext.style.bottom = (100 - parseFloat(fNode.height)) + "%";
}
if (this.$handle) {
this.$handle.$ext.style.top = isPercentage
? fNode.height
: ((parseInt(fNode.height) + this.$edge[0]) + "px");
// this.$handle.$ext.style.marginTop = isPercentage
// ? this.padding + "px"
// : "0";
}
}
else {
isPercentage = String(lNode.height).indexOf("%") > -1;
lNode.$ext.style.top = "";
fNode.$ext.style.bottom = isPercentage
? lNode.height
: ((parseInt(lNode.height) + this.padding
+ this.$edge[2] + lNode.$margin[2]) + "px");
if (isPercentage) {
lNode.$ext.style.height = "";
lNode.$ext.style.top = (100 - parseFloat(lNode.height)) + "%";
}
if (this.$handle) {
this.$handle.$ext.style.bottom = isPercentage
? lNode.height
: ((parseInt(lNode.height) + this.$edge[0]) + "px");
// this.$handle.$ext.style.marginBottom = isPercentage
// ? this.padding + "px"
// : "0";
}
}
if (this.$handle) {
this.$handle.$ext.style.left = this.$edge[3] + "px";
this.$handle.$ext.style.right = this.$edge[1] + "px";
}
}
else {
lNode.$ext.style.top = this.$edge[0] + lNode.$margin[0] + "px";
if (fNode.width || fNode.width === 0) {
var isPercentage = String(fNode.width).indexOf("%") > -1;
lNode.$ext.style.left = isPercentage
? fNode.width
: ((parseInt(fNode.width) + this.padding
+ this.$edge[3] + fNode.$margin[3]) + "px");
if (isPercentage) {
fNode.$ext.style.width = "";
fNode.$ext.style.right = (100 - parseFloat(fNode.width)) + "%";
}
if (this.$handle) {
this.$handle.$ext.style.left = isPercentage
? fNode.width
: ((parseInt(fNode.width) + this.$edge[3]) + "px");
// this.$handle.$ext.style.marginLeft = isPercentage
// ? this.padding + "px"
// : "0";
}
}
else {
var isPercentage = String(lNode.width).indexOf("%") > -1;
lNode.$ext.style.left = "";
fNode.$ext.style.right = isPercentage
? lNode.width
: ((parseInt(lNode.width) + this.padding
+ this.$edge[1] + lNode.$margin[1]) + "px");
if (isPercentage) {
lNode.$ext.style.width = "";
lNode.$ext.style.left = (100 - parseFloat(lNode.width)) + "%";
}
if (this.$handle) {
this.$handle.$ext.style.right = isPercentage
? lNode.width
: ((parseInt(lNode.width) + this.$edge[3]) + "px");
// this.$handle.$ext.style.marginRight = isPercentage
// ? this.padding + "px"
// : "0";
}
}
if (this.$handle) {
this.$handle.$ext.style.top = this.$edge[0] + "px";
this.$handle.$ext.style.bottom = this.$edge[2] + "px";
}
}
if (this.$handle)
this.$handle.$ext.style.position = "absolute";
}
else {
if (!this.$vbox) {
fNode.$ext.style.right = (this.$edge[1] + fNode.$margin[1]) + "px";
fNode.$ext.style.width = "";
}
else {
fNode.$ext.style.bottom = (this.$edge[2] + fNode.$margin[2]) + "px";
fNode.$ext.style.height = "";
}
if (this.$handle)
this.$handle.hide();
}
if (setSize === true) {
var size = this.$vbox ? "height" : "width";
fNode.$propHandlers[size].call(fNode, fNode[size]);
}
};
this.getFirstChild = function(startNode) {
var node = startNode || this.firstChild;
while (node && node.$splitter) {
node = node.nextSibling;
}
return node || false;
}
this.getSecondChild = function(){
var node = this.getFirstChild();
if (!node)
return false;
return node.nextSibling && this.getFirstChild(node.nextSibling);
}
this.getFirstVisibleChild = function(startNode) {
var node = startNode || this.firstChild;
while (node && (!node.visible || node.$splitter)) {
node = node.nextSibling;
}
if (node && node.visible)
return node;
return false;
}
this.getSecondVisibleChild = function(){
var node = this.getFirstVisibleChild();
if (!node)
return false;
return node.nextSibling && this.getFirstVisibleChild(node.nextSibling);
}
function visibleHandler(e) {
if (this.parentNode.$handle) {
if (!e.value || this.parentNode.childNodes.length < 3)
this.parentNode.$handle.hide();
else
this.parentNode.$handle.show();
}
if (e.value && !this.parentNode.visible)
this.parentNode.show();
this.parentNode.$propHandlers.edge
.call(this.parentNode, this.parentNode.edge, true);
// apf.layout.forceResize(this.parentNode.$int);
//Change margin
this.parentNode.$propHandlers.padding
.call(this.parentNode, this.parentNode.padding)
}
var handlers = {
"width" : function(value, isLast) {
//@todo this should check the largest and only allow that one
//if (this.parentNode.$vbox && this.parentNode.align == "stretch")
//return;
//@todo change fixedChild flexChild1 and flexChild2 based on this
this.$ext.style.width = !apf.isNot(value)
? (parseFloat(value) == value
? (value - apf.getWidthDiff(this.$ext)) + "px"
: value)
: "";
//This can be optimized
if (this.$amlLoaded && isLast !== false)
this.parentNode.$propHandlers["edge"].call(this.parentNode,
this.parentNode.edge);
},
"height" : function(value, isLast) {
//@todo this should check the largest and only allow that one
//if (!this.parentNode.$vbox && this.parentNode.align == "stretch")
//return;
//@todo change fixedChild flexChild1 and flexChild2 based on this
this.$ext.style.height = !apf.isNot(value)
? (parseFloat(value) == value
? (value - apf.getHeightDiff(this.$ext)) + "px"
: value)
: "";
//This can be optimized
if (this.$amlLoaded && isLast !== false)
this.parentNode.$propHandlers["edge"].call(this.parentNode,
this.parentNode.edge);
},
"margin" : function(value, isLast) {
this.$margin = apf.getBox(value);
//This can be optimized
if (this.$amlLoaded && isLast !== false)
this.parentNode.$propHandlers["edge"].call(this.parentNode, this.parentNode.edge);
}
}
this.register = function(amlNode, insert) {
if (amlNode.$splitter || amlNode.nodeFunc != apf.NODE_VISIBLE)
return;
amlNode.$margin = [0, 0, 0, 0];
amlNode.$propHandlers["left"] =
amlNode.$propHandlers["top"] =
amlNode.$propHandlers["right"] =
amlNode.$propHandlers["bottom"] = apf.K;
for (var prop in handlers) {
amlNode.$propHandlers[prop] = handlers[prop];
}
var fNode = this.getFirstChild();
var sNode = fNode && this.getSecondChild();
var prop = this.$vbox ? "height" : "width";
this.flexChild1 = this.flexChild2 = this.fixedChild = null;
if (!fNode[prop] || ~String(fNode[prop]).indexOf("%"))
this.flexChild1 = fNode;
else
this.fixedChild = fNode;
if (sNode) {
if (!sNode[prop] || ~String(sNode[prop]).indexOf("%"))
this[this.flexChild1 ? "flexChild2" : "flexChild1"] = sNode;
else
this.fixedChild = sNode;
}
// if (this.flexChild1 && this.flexChild1 == amlNode){ }
// else if (this.$vbox) {
// if (!amlNode.height || String(amlNode.height).indexOf("%") > -1)
// this[!this.flexChild1 ? "flexChild1" : "flexChild2"] = amlNode;
// else
// this.fixedChild = amlNode;
// }
// else {
// if (!amlNode.width || String(amlNode.width).indexOf("%") > -1)
// this[!this.flexChild1 ? "flexChild1" : "flexChild2"] = amlNode;
// else
// this.fixedChild = amlNode;
// }
amlNode.addEventListener("prop.visible", visibleHandler);
amlNode.$ext.style.position = "absolute";
amlNode.$ext.style.margin = "";
if (amlNode.height)
handlers.height.call(amlNode, amlNode.height, false);
if (amlNode.width)
handlers.width.call(amlNode, amlNode.width, false);
if (amlNode.margin)
handlers.margin.call(amlNode, amlNode.margin, false);
var isLast = this.lastChild.$amlLoaded || this.lastChild == amlNode;
if (isLast) {
this.$propHandlers["padding"].call(this, this.padding);
this.$propHandlers["edge"].call(this, this.edge,
!amlNode[this.$vbox ? "height" : "width"]);
}
if (this.$handle && this.childNodes.length > 2)
this.$handle.show();
}
this.unregister = function(amlNode) {
if (amlNode.$splitter || amlNode.nodeFunc != apf.NODE_VISIBLE)
return;
delete amlNode.$margin;
amlNode.$propHandlers["left"] =
amlNode.$propHandlers["top"] =
amlNode.$propHandlers["right"] =
amlNode.$propHandlers["bottom"] = null;
for (var prop in handlers) {
delete amlNode.$propHandlers[prop];
}
if (this.fixedChild == amlNode)
delete this.fixedChild;
else if (this.flexChild1 == amlNode)
delete this.flexChild1;
else if (this.flexChild2 == amlNode)
delete this.flexChild2;
//Clear css properties and set layout
amlNode.removeEventListener("prop.visible", visibleHandler);
amlNode.$ext.style.display = amlNode.visible ? "block" : "none";
if (amlNode.width)
amlNode.$ext.style.width = "";
if (amlNode.height)
amlNode.$ext.style.height = "";
amlNode.$ext.style.position =
amlNode.$ext.style.margin =
amlNode.$ext.style.left =
amlNode.$ext.style.top =
amlNode.$ext.style.right =
amlNode.$ext.style.bottom = "";
if (this.$handle)
this.$handle.hide();
}
// *** DOM Hooks *** //
this.addEventListener("DOMNodeRemoved", function(e) {
if (e.$doOnlyAdmin || e.currentTarget == this)
return;
if (e.relatedNode == this) {
this.unregister(e.currentTarget);
//e.currentTarget.$setLayout();
}
});
this.addEventListener("DOMNodeInserted", function(e) {
if (e.currentTarget == this) {
return;
}
if (e.currentTarget.nodeType != 1
|| e.currentTarget.nodeFunc != apf.NODE_VISIBLE)
return;
// if (this.$handle) {
// var _self = this;
// setTimeout(function(){
// if (_self.$handle.nextSibling != _self.lastChild)
// _self.insertBefore(_self.$handle, _self.lastChild);
// });
// }
if (e.relatedNode == this && !e.$isMoveWithinParent) {
e.currentTarget.$setLayout(this.localName, true);
if (e.currentTarget.$altExt) {
return false;
}
}
});
this.$draw = function(){
var doc = this.$pHtmlNode.ownerDocument;
this.$ext = this.$pHtmlNode.appendChild(doc.createElement("div"));
if (this.getAttribute("style"))
this.$ext.setAttribute("style", this.getAttribute("style"));
this.$ext.className = this.localName;
this.$vbox = this.localName == "vsplitbox";
this.$int = this.$ext;
this.$ext.host = this;
if (this.getAttribute("class"))
apf.setStyleClass(this.$ext, this.getAttribute("class"));
};
this.$loadAml = function(x) {
};
}).call(apf.vsplitbox.prototype = new apf.GuiElement());
apf.hsplitbox.prototype = apf.vsplitbox.prototype;
apf.aml.setElement("hsplitbox", apf.hsplitbox);
apf.aml.setElement("vsplitbox", apf.vsplitbox);
/**
* @constructor
* @private
*/
apf.splitter = function(struct, tagName) {
this.$init(tagName || "splitter", apf.NODE_VISIBLE, struct);
};
(function() {
this.minwidth = 0;
this.minheight = 0;
this.$scale = 0; // 0 both, 1 left/top, 2 right/bottom
this.$focussable = false; // This object can get the focus
this.$splitter = true;
this.$booleanProperties["realtime"] = true;
this.$propHandlers["realtime"] = function(value) {
this.$setStyleClass(this.$ext, value && (this.$baseCSSname + "Realtime") || "",
[this.$baseCSSname + "Realtime"]);
};
this.$propHandlers["scale"] = function(value) {
this.$scale = value == "left" || value == "top"
? 1 : (value == "right" || "bottom "
? 2 : 0);
};
this.$propHandlers["parent"] = function(value) {
this.$parent = typeof value == "object" ? value : self[value];
};
this.$propHandlers["type"] = function(value) {
this.$setStyleClass(this.$ext, value,
[value == "horizontal" ? "vertical" : "horizontal"]);
if (value == "vertical")
this.$setStyleClass(this.$ext, "w-resize", ["n-resize"]);
else
this.$setStyleClass(this.$ext, "n-resize", ["w-resize"]);
//Optimize this to not recalc for certain cases
if (value == "horizontal") {
this.$info = {
pos: "top",
opos: "left",
size: "width",
osize: "height",
offsetPos: "offsetTop",
offsetSize: "offsetHeight",
oOffsetPos: "offsetLeft",
oOffsetSize: "offsetWidth",
clientPos: "clientY",
d1 : 1,
d2 : 0,
x1 : 0,
x2 : 2
};
}
else {
this.$info = {
pos: "left",
opos: "top",
size: "height",
osize: "width",
offsetPos: "offsetLeft",
offsetSize: "offsetWidth",
oOffsetPos: "offsetTop",
oOffsetSize: "offsetHeight",
clientPos: "clientX",
d1 : 0,
d2 : 1,
x1 : 3,
x2 : 1
};
}
};
this.addEventListener("DOMNodeInserted", function(e) {
if (e.currentTarget != this)
return;
/*if (e.$oldParent) {
e.$oldParent.removeEventListener("DOMNodeInserted", this.$siblingChange);
e.$oldParent.removeEventListener("DOMNodeRemoved", this.$siblingChange);
}*/
this.init && this.init();
});
/*this.$siblingChange = function(e) {
//if (e.currentTarget
//this.init();
}*/
this.$draw = function(){
//Build Main Skin
this.$ext = this.$getExternal();
var template = "vbox|hbox".indexOf(this.parentNode.localName) > -1
? "box" : "splitbox";
apf.extend(this, apf.splitter.templates[template]);
this.decorate();
};
this.$loadAml = function(x) {
if (this.realtime !== false)
this.$propHandlers.realtime.call(this, this.realtime = true);
};
}).call(apf.splitter.prototype = new apf.Presentation());
apf.splitter.templates = {
box: {
update: function(newPos, finalPass) {
with (this.$info) {
//var pos = Math.ceil(apf.getAbsolutePosition(this.$ext, this.parentNode.$int)[d1] - posPrev[d1]);
var max = this.$previous
? this.$previous.$ext[offsetSize] + this.$next.$ext[offsetSize]
: (this.parentNode).getWidth();
var method = finalPass ? "setAttribute" : "setProperty";
if (apf.hasFlexibleBox)
newPos -= this.$previous ? apf.getAbsolutePosition(this.$previous.$ext, this.parentNode.$int)[d1] : 0;
//Both flex
if (this.$previous && this.$next && (this.$previous.flex || this.$previous.flex === 0) && (this.$next.flex || this.$next.flex === 0)) {
if (!finalPass && !this.realtime)
newPos -= this.$ext[offsetSize];
//var totalFlex = this.$previous.flex + this.$next.flex - (finalPass && !this.realtime ? this.parentNode.padding : 0);
if (!this.$scale || this.$scale == 1)
this.$previous[method]("flex", newPos);
if (!this.$scale || this.$scale == 2)
this.$next[method]("flex", this.$totalFlex - newPos);
}
//Fixed
else {
if (this.$next && !this.$next.flex && (!this.$scale || this.$scale == 2))
this.$next[method](osize, max - newPos);
if (this.$previous && !this.$previous.flex && (!this.$scale || this.$scale == 1))
this.$previous[method](osize, newPos);
}
}
if (apf.hasSingleResizeEvent)
apf.layout.forceResize(this.$ext.parentNode);
},
$setSiblings: function(){
this.$previous = this.previousSibling;
while (this.$previous && (this.$previous.nodeType != 1
|| this.$previous.visible === false
|| this.$previous.nodeFunc != apf.NODE_VISIBLE))
this.$previous = this.$previous.previousSibling;
this.$next = this.nextSibling;
while (this.$next && (this.$next.nodeType != 1
|| this.$next.visible === false
|| this.$next.nodeFunc != apf.NODE_VISIBLE))
this.$next = this.$next.nextSibling;
},
init: function(size, refNode, oItem) {
//this.parentNode.addEventListener("DOMNodeInserted", this.$siblingChange);
//this.parentNode.addEventListener("DOMNodeRemoved", this.$siblingChange);
this.$setSiblings();
this.$thickness = null;
if (this.parentNode && this.parentNode.$box) {
this.setProperty("type", this.parentNode.localName == "vbox"
? "horizontal"
: "vertical");
this.$thickness = parseInt(this.parentNode.padding);
}
if (!this.$previous || !this.$next)
return this;
with (this.$info) {
var diff = apf.getDiff(this.$ext);
if (!this.parentNode.$box) {
var iSize = Math.max(
this.$previous.$ext[offsetSize], this.$next.$ext[offsetSize]);
this.$ext.style[size] = (iSize - diff[d1]) + "px";
}
var iThick = this[osize] = this.$thickness
|| (this.$next[oOffsetPos] - this.$previous[oOffsetPos]
- this.$previous[oOffsetSize]);
this.$ext.style[osize] = (iThick - diff[d2]) + "px";
}
return this;
},
decorate: function(){
var _self = this;
this.$ext.onmousedown = function(e) {
if (!e)
e = event;
if (_self.dispatchEvent("dragstart") === false)
return;
apf.dragMode = true; //prevent selection
_self.$setSiblings();
var changedPosition, pHtml = _self.parentNode.$int, diff = 0;
if ("absolute|fixed|relative".indexOf(apf.getStyle(pHtml, "position")) == -1) {
pHtml.style.position = "relative";
changedPosition = true;
}
_self.$totalFlex = 0;
with (_self.$info) {
if (_self.$parent) {
if (!_self.$previous) {
var posNext = apf.getAbsolutePosition(_self.$next.$ext, _self.parentNode.$int);
var wd = _self.$parent.getWidth();
if (_self.$scale == 2) {
var max = posNext[d1] + _self.$next.$ext[offsetSize] - this[offsetSize];
diff = (_self.parentNode.$int[offsetSize] - max);
var min = max - wd - diff;
}
}
else if (!_self.$next) {
//@todo
}
}
else {
if (_self.$previous) {
var posPrev = apf.getAbsolutePosition(_self.$previous.$ext, _self.parentNode.$int);
var min = _self.$scale
? 0
: (posPrev[d1] || 0) + (parseInt(_self.$previous.minwidth) || 0);
}
if (_self.$next) {
var posNext = apf.getAbsolutePosition(_self.$next.$ext, _self.parentNode.$int);
var max = posNext[d1] + _self.$next.$ext[offsetSize]
- this[offsetSize] - (parseInt(_self.$next.minwidth) || 0);
}
}
//Set flex to pixel sizes
if (_self.$previous && _self.$next) {
if ((_self.$previous.flex || _self.$previous.flex === 0)
&& (_self.$next.flex || _self.$next.flex === 0)) {
var set = [], nodes = _self.parentNode.childNodes, padding = 0;
for (var node, i = 0, l = nodes.length; i < l; i++) {
if ((node = nodes[i]).visible === false
|| node.nodeFunc != apf.NODE_VISIBLE || node.$splitter)
continue;
if (node.flex)
set.push(node, node.$ext[offsetSize]
+ (apf.hasFlexibleBox && !_self.realtime && node == _self.$previous
? 2 * _self.parentNode.padding : 0));
}
for (var i = 0, l = set.length; i < l; i+=2) {
set[i].setAttribute("flex", set[i+1]);
}
}
_self.$totalFlex += _self.$next.flex + _self.$previous.flex;
}
var startPos, startOffset;
if (apf.hasFlexibleBox) {
var coords = apf.getAbsolutePosition(this);
startPos = e[clientPos] - coords[d1];
if (!_self.realtime) {
if (_self.$previous.flex && !_self.$next.flex) {
var mBox = apf.getBox(_self.$next.margin);
mBox[x1] = _self.parentNode.padding;
_self.$next.$ext.style.margin = mBox.join("px ") + "px";
}
else {
var mBox = apf.getBox(_self.$previous.margin);
mBox[x2] = _self.parentNode.padding;
_self.$previous.$ext.style.margin = mBox.join("px ") + "px";
}
var diff = apf.getDiff(this);
this.style.left = coords[0] + "px";
this.style.top = coords[1] + "px"; //(apf.getHtmlTop(this) - Math.ceil(this.offsetHeight/2))
this.style.width = (this.offsetWidth - diff[0]) + "px";
this.style.height = (this.offsetHeight - diff[1]) + "px";
this.style.position = "absolute";
}
}
else {
var coords = apf.getAbsolutePosition(this.offsetParent);
startOffset = apf.getAbsolutePosition(_self.$previous.$ext)[d1];
startPos = e[clientPos] - coords[d1];
if (!_self.realtime) {
this.style.left = "0px";
this.style.top = "0px";
this.style.position = "relative";
}
min = -1000; //@todo
}
}
//e.returnValue = false;
//e.cancelBubble = true;
//apf.stopEvent(e);
apf.plane.show(this);
_self.$setStyleClass(this, _self.$baseCSSname + "Moving");
_self.$setStyleClass(document.body,
_self.type == "vertical" ? "w-resize" : "n-resize",
[_self.type == "vertical" ? "n-resize" : "w-resize"]);
//@todo convert to proper way
document.onmouseup = function(e) {
if (!e) e = event;
with (_self.$info) {
var newPos;
if (e[clientPos] >= 0) {
var coords = apf.getAbsolutePosition(_self.$ext.offsetParent);
newPos = (Math.min(max, Math.max(min, (e[clientPos] - coords[d1]) -
(apf.hasFlexibleBox ? startPos : startOffset)))) + diff;
}
}
_self.$setStyleClass(_self.$ext, "", [_self.$baseCSSname + "Moving"]);
_self.$setStyleClass(document.body, "", ["n-resize", "w-resize"]);
if (changedPosition)
pHtml.style.position = "";
if (apf.hasFlexibleBox && !_self.realtime)
(_self.$previous.flex && !_self.$next.flex
? _self.$next : _self.$previous).$ext.style.margin
= apf.getBox(_self.$previous.margin).join("px ") + "px";
if (newPos)
_self.update(newPos, true);
apf.plane.hide();
if (!_self.realtime) {
_self.$ext.style.left = "";
_self.$ext.style.top = "";
_self.$ext.style[_self.$info.size] = "";
_self.$ext.style.position = "";
}
_self.dispatchEvent("dragdrop");
document.onmouseup =
document.onmousemove = null;
apf.dragMode = false; //return to default selection policy
};
//@todo convert to proper way
document.onmousemove = function(e) {
if (!e) e = event;
with (_self.$info) {
var newPos;
if (e[clientPos] >= 0) {
var coords = apf.getAbsolutePosition(_self.$ext.offsetParent);
newPos = (Math.min(max, Math.max(min, (e[clientPos] - coords[d1]) -
(apf.hasFlexibleBox || !_self.realtime ? startPos : startOffset)))) + diff;
if (_self.realtime)
_self.update(newPos);
else {
_self.$ext.style[pos] = newPos + "px";
}
}
}
apf.stopEvent(e);
//e.returnValue = false;
//e.cancelBubble = true;
_self.dispatchEvent("dragmove");
};
}
apf.queue.add("splitter" + this.$uniqueId, function(){
_self.init();
});
}
},
splitbox: {
update: function(newPos, finalPass) {
this[this.parentNode.$vbox ? "updateV" : "updateH"](newPos, finalPass);
},
updateV: function(newPos, finalPass) {
var method = finalPass ? "setAttribute" : "setProperty";
var pNode = this.$parent || this.parentNode;
var firstChild = pNode.firstChild;
if (firstChild.localName == "splitter")
firstChild = firstChild.nextSibling;
if (pNode.fixedChild) {
if (pNode.fixedChild == pNode.firstChild) {
pNode.fixedChild[method]("height", newPos - pNode.$edge[0]);
}
else {
pNode.fixedChild[method]("height",
apf.getHtmlInnerHeight(pNode.$int) - newPos
- pNode.padding - pNode.$edge[1]);
}
}
else if (firstChild.height) {
var total = apf.getHtmlInnerHeight(pNode.$int);
firstChild[method]("height",
((newPos - pNode.$edge[0])/total*100) + "%");
}
else {
var total = apf.getHtmlInnerHeight(pNode.$int) ;
pNode.lastChild[method]("height",
((total - newPos - pNode.$edge[2] - pNode.padding)/total*100) + "%");
}
apf.dispatchEvent("splitter.resize", { splitter: this, final: finalPass });
},
updateH: function(newPos, finalPass) {
var method = finalPass ? "setAttribute" : "setProperty";
var pNode = this.$parent || this.parentNode;
var firstChild = pNode.firstChild;
if (firstChild.localName == "splitter")
firstChild = firstChild.nextSibling;
if (pNode.fixedChild) {
if (pNode.fixedChild == pNode.firstChild) {
pNode.fixedChild[method]("width", newPos - pNode.$edge[3]);
}
else {
pNode.fixedChild[method]("width",
apf.getHtmlInnerWidth(pNode.$int) - newPos
- pNode.padding - pNode.$edge[2]);
}
}
else if (firstChild.width) {
var total = apf.getHtmlInnerWidth(pNode.$int);
firstChild[method]("width",
((newPos - pNode.$edge[3])/total*100) + "%");
}
else {
var total = apf.getHtmlInnerWidth(pNode.$int) ;
pNode.lastChild[method]("width",
((total - newPos - pNode.$edge[1] - pNode.padding)/total*100) + "%");
}
apf.dispatchEvent("splitter.resize", { splitter: this, final: finalPass });
},
$setSiblings: function(){
this.$previous = this.parentNode.firstChild;
this.$next = this.parentNode.lastChild;
},
decorate: function(){
var _self = this;
if (this.parentNode && this.parentNode.$box) {
this.setProperty("type", this.parentNode.$vbox
? "horizontal"
: "vertical");
}
this.$ext.onmousedown = function(e) {
if (!e)
e = event;
if (_self.dispatchEvent("dragstart") === false)
return;
apf.dragMode = true; //prevent selection
_self.$setSiblings();
var pNode = _self.$parent || _self.parentNode;
var firstChild = pNode.firstChild.$splitter ? pNode.childNodes[1] : pNode.firstChild;
if (pNode.$vbox) {
var min = parseInt(firstChild.minheight) + pNode.$edge[0];
var max = apf.getHtmlInnerHeight(pNode.$ext) - pNode.lastChild.minheight
- pNode.$edge[2] - pNode.padding;
var offset = _self.$ext.getBoundingClientRect().top - e.clientY;
}
else {
var min = parseInt(firstChild.minwidth) + pNode.$edge[3];
var max = apf.getHtmlInnerWidth(pNode.$ext) - pNode.lastChild.minwidth
- pNode.$edge[1] - pNode.padding;
var offset = _self.$ext.getBoundingClientRect().left - e.clientX;
}
function update(e, final) {
if (!_self.$ext.offsetParent)
return;
var newPos, coords;
if (pNode.$vbox) {
if (e.clientY >= 0) {
coords = apf.getAbsolutePosition(_self.$parent ? _self.$parent.$ext : _self.$ext.offsetParent);
newPos = Math.min(max, Math.max(min, (e.clientY - coords[1] - offset)));
}
}
else {
if (e.clientX >= 0) {
coords = apf.getAbsolutePosition(_self.$parent ? _self.$parent.$ext : _self.$ext.offsetParent);
newPos = Math.min(max, Math.max(min, (e.clientX - coords[0] - offset)));
}
}
if (!newPos) return;
if (_self.realtime || final)
_self.update(newPos, final);
else {
_self.$ext.style[pNode.$vbox ? "top" : "left"] = newPos + "px";
}
}
apf.plane.show(this);
_self.$setStyleClass(this, _self.$baseCSSname + "Moving");
_self.$setStyleClass(document.body,
_self.type == "vertical" ? "w-resize" : "n-resize",
[_self.type == "vertical" ? "n-resize" : "w-resize"]);
//@todo convert to proper way
document.onmouseup = function(e) {
if (!e) e = event;
_self.$setStyleClass(_self.$ext, "", [_self.$baseCSSname + "Moving"]);
_self.$setStyleClass(document.body, "", ["n-resize", "w-resize"]);
update(e, true);
apf.plane.hide();
// Return all pointer events to iframes
var frames = document.getElementsByTagName("iframe");
for (var i = 0; i < frames.length; i++)
frames[i].style.pointerEvents = "";
if (!_self.realtime) {
_self.$ext.style.left = "";
_self.$ext.style.top = "";
_self.$ext.style[_self.$info.size] = "";
_self.$ext.style.position = "";
}
_self.dispatchEvent("dragdrop");
document.onmouseup =
document.onmousemove = null;
apf.dragMode = false; //return to default selection policy
};
//@todo convert to proper way
document.onmousemove = function(e) {
if (!e) e = event;
update(e);
apf.stopEvent(e);
//e.returnValue = false;
//e.cancelBubble = true;
_self.dispatchEvent("dragmove");
};
}
}
}
};
apf.aml.setElement("splitter", apf.splitter);
};
});