@doc hierarchy="GMLDOM">
Base aspect for all objects editable by Layout Editor.
This includes: Container, ScenarioUsage, Interactor, Control
(c) SAP AG 2003-2006. All rights reserved.
Aspect Widget for Layout;
// implement ILayoutable; // Uncomment when parser starts to support this
virtual property opacity = 1;
// Layoutable type: none | diagram | box | control | viewbar | toolbar
virtual property type = 'none';
virtual property arrowImageTopShift = 12; //[[imageHeigth(42px) - controlHeight(16px)] / 2] - 1
virtual property isRendered = false;
constructor(board, parent)
// if (!board) throw new Error('Failed to create Widget. No "board" supplied');
if (!board) throw new Error('#TEXT[XMSG_FAIL_DISPLAY_LAYOUT_BOARD]');
this.id = base.id;
this.board = board; // board object (LayoutEditor object)
this.parentID = parent.id; // Parent Aspect object
this.doc = board.document;
this.diagramID = parent.diagramID || this.parentID;
board.setWidget(this);
this.elem = null; // This HTML element
this.parentElement = null; // Parent HTML element
//
// Find closest parent 'box' object
//
var lobj = parent;
while (lobj && lobj.type != 'box') lobj = lobj.getParent();
this.boxID = lobj && lobj.id;
end
destructor()
end
virtual method getBox()
return this.board.getWidget(this.boxID);
end
virtual method getParent()
return this.board.getWidget(this.parentID)||this.getDiagram();
end
virtual method getDiagram()
if (this.diagramID == this.board.diagram.id) return this.board.diagram;
return this.board.getWidget(this.diagramID);
end
///////////////////////////////////////////////////////////////////////////
// ILayoutable implementation
// parentElement is null by default - means that it's this.getParent().elem
override virtual method paint(parentElement)
var parent = parentElement ? null : this.getParent();
this.parentElement = parentElement || (parent && parent.elem) || this.board.canvas;
end
override virtual method repaint(attr)
end
/*
<@method name="setZOrder">
Sets the box layer
The new z order index
// VC04: METHOD('setLayer', function(z) {
override virtual method setZOrder(z)
var elem = this.elem; if (!elem) return;
elem.z = INT(z);
elem.style.zIndex = elem.z;
end
*/
<@method name="setPos">
Sets the widget position
The new position
Indicates whether to snap to the nearest valid position
// VC04: METHOD('setPos', function(x, y, snap) {
virtual method setPos(pos, snap)
var elem = this.elem; if (!elem) return;
elem.x = snap ? ROUND(INT(pos.x), elem.gs||0) : INT(pos.x);
elem.y = snap ? ROUND(INT(pos.y), elem.gs||0) : INT(pos.y);
var st = elem.style;
st.left = elem.x;
st.top = elem.y;
end
<@method name="capturePos">
Called once before starting a move operation.
This method can be used to capture the box position before it is moved.
// VC04: METHOD('capturePos', function() {
virtual method capturePos()
// override
end
<@method name="applyPos">
Called once after finishing a move operation.
This method can be used to apply custom behavior when the box is moved
// VC04: METHOD('applyPos', function() {
virtual method applyPos()
// override
end
<@method name="setSize">
Sets the box size
The new width
The new height
Indicates whether to snap to the nearest valid size
// VC04: METHOD('setSize', function(w, h, snap) {
virtual method setSize(size, snap)
var elem = this.elem; if (!elem) return;
elem.w = snap ? ROUND(INT(size.w), elem.gs||0) : INT(size.w);
elem.h = snap ? ROUND(INT(size.h), elem.gs||0) : INT(size.h);
if (elem.w < 0) elem.w = 0;
if (elem.h < 0) elem.h = 0;
var st = elem.style;
st.width = elem.w; // st.width = elem.w+1;
st.height = elem.h; // st.height = elem.h+1; // NOTE: Why VC04 has +1 here?
end
<@method name="setRect">
Sets the box position and size
The new rectangle containing position and size
Indicates whether to snap to the nearest valid size
// VC04: METHOD('setBBox', function(x, y, w, h, snap) {
virtual method setRect(rect, snap)
this.setPos({x: rect.x, y: rect.y}, snap);
this.setSize({w: rect.w, h: rect.h}, snap);
end
<@method name="captureBBox">
Called once before starting a resize operation.
This method can be used to capture the box sized before it is resized.
// VC04: METHOD('captureBBox', function() {
virtual method captureRect()
// override
end
<@method name="applyRect">
Called once after finishing a resize operation.
This method can be used to apply custom behavior when the box is resized
virtual method applyRect() // VC04: METHOD('applyBBox', function() {
// override
end
<@method name="resetRect">
Resets the box position and size to cancel any pending move/resize operation
virtual method resetRect()
// NOTE: consider moving this to SelectionMgr if there's no reason for overrides
var elem = this.elem; if (!elem) return;
if (!elem.oldx || !elem.oldy || !elem.oldw || !elem.oldh) return;
this.setPos({x: elem.oldx, y: elem.oldy}, true);
this.setSize({w: elem.oldw, h: elem.oldh}, true);
end
<@method name="setVisibility">
Sets the box visibility
The box opacity level, between 0 (invisible) and 1 (visible)
virtual method setVisibility(opacity) // VC04: METHOD('setVisibility', function(opacity) {
var elem = this.elem; if (!elem) return;
if (POS(this.opacity) == opacity) return;
var st = elem.style; //var st=this.style;
if (opacity <= 0 ) {
st.visibility = 'hidden';
st.filter = 'none';
} else if (opacity >= 1 ) {
st.visibility = 'inherit';
st.filter = 'none';
} else {
st.visibility = 'inherit';
st.filter = 'alpha(opacity='+(opacity*100)+')';
}
this.opacity = opacity;
end
virtual method applyLayout(focusWidget, operation, repaint)
return false;
end
virtual method buildRearrangeParams(focusWidget, operation, contentsSize, syncElems)
return null;
end
override virtual method updateElements(operation, syncElems)
var rootInfo = this.buildRearrangeParams(null, operation, undefined, syncElems);
if (!rootInfo) return;
var changes = this.board.getChangesFromCache(rootInfo&&rootInfo.focus);
RULE('rearrangeWidgets', base, this.board, rootInfo, changes);
if (!ISEMPTY(changes)) RULE('doApplyLayout', base, changes);
end
virtual method getPos()
if (!this.elem) return {x: 0, y: 0};
return {x: this.elem.offsetLeft, y: this.elem.offsetTop};
end
virtual method getSize()
if (!this.elem) return {w: 320, h: 200};
return {w: this.elem.offsetWidth, h: this.elem.offsetHeight};
end
virtual method getRect()
var pos = this.getPos();
var size = this.getSize();
return {x: pos.x, y: pos.y, w: size.w, h: size.h};
end
<@method name="setResizePolicy">
Updates box resize policy, used by Selection Manager
virtual method setResizePolicy(policy)
var sel = this.board.selection; if (!this.elem || !sel) return;
if (typeof policy == 'number') {
var p = null;
switch (policy) {
case #[LYT_MOVE_VERT]: p = {moveH: false, moveV: true, resizeH: true, resizeV: true }; break;
case #[LYT_MOVE_HORZ]: p = {moveH: true, moveV: false, resizeH: true, resizeV: true }; break;
case #[LYT_RESIZE_FIXED]: p = {moveH: false, moveV: false, resizeH: false, resizeV: false}; break;
case #[LYT_RESIZE_FREE]: p = {moveH: true, moveV: true, resizeH: true, resizeV: true }; break;
case #[LYT_RESIZE_HORZ]: p = {moveH: true, moveV: true, resizeH: true, resizeV: false}; break;
case #[LYT_RESIZE_VERT]: p = {moveH: true, moveV: true, resizeH: false, resizeV: true }; break;
case #[LYT_MOVERESIZE_HORZ]: p = {moveH: true, moveV: false, resizeH: true, resizeV: false}; break;
case #[LYT_MOVERESIZE_HORZ_LEFT]: p = {moveH: true, moveV: true, resizeH: true, resizeV: false, alignH: 1, cursor: #[LYT_COL_RESIZE]}; break;
case #[LYT_MOVE_HORZ_RESIZE_HORZ_LEFT]: p = {moveH: true, moveV: false, resizeH: true, resizeV: false, alignH: 1, cursor: #[LYT_COL_RESIZE]}; break;
case #[LYT_MOVERESIZE_HORZ_RIGHT]: p = {moveH: true, moveV: true, resizeH: true, resizeV: false, alignH: -1, cursor: #[LYT_COL_RESIZE]}; break;
case #[LYT_MOVE_NO_RESIZE_HORZ]: p = {moveH: true, moveV: true, resizeH: false, resizeV: false}; break;
case #[LYT_MOVE_HORZ_NO_RESIZE]: p = {moveH: true, moveV: false, resizeH: false, resizeV: false}; break;
case #[LYT_MOVEVERT_RESIZE_SE]: p = {moveH: false, moveV: true, resizeH: true, resizeV: true, alignH: 1, alignV: 1}; break;
case #[LYT_MOVEHORZ_RESIZE_SE]: p = {moveH: true, moveV: false, resizeH: true, resizeV: true, alignH: 1, alignV: 1}; break;
case #[LYT_RESIZE_SE]: p = {moveH: true, moveV: true, resizeH: true, resizeV: true, alignH: 1, alignV: 1}; break;
case #[LYT_MOVERESIZE_VERT_BOTTOM]: p = {moveH: true, moveV: true, resizeH: false, resizeV: true, alignV: 1, cursor: #[LYT_ROW_RESIZE]}; break;
}
policy = p;
}
this.elem.style.resizePolicy = sel.encodeResizePolicy(policy);
end
<@doc scope="private">
Handles an update of base object property
virtual method onModelUpdate(evt)
end
<@doc scope="private">
Handles an insertion of a child object into base object
virtual method onModelInsert(evt)
end
<@doc scope="private">
Handles a removal of a child object from the base object
virtual method onModelRemove(evt)
end
// DOC: derived implementations should also take care of setBaseRect
virtual method setBasePos(pos)
// Convert HTML event coordinates (elem.offsetParent-relative) - convert it to parent.content-relative
var parent = this.getParent();
if (parent && this.elem) pos = parent.offsetToContent(this.elem.offsetParent, pos);
RULE('setWidgetDimensions', base, pos, null, null, this.board.sessionCache);
end
virtual method setBaseSize(size)
RULE('setWidgetDimensions', base, null, size, null, this.board.sessionCache);
end
// DOC: derived implementations should also take care of setBasePos
virtual method setBaseRect(rect)
// Convert HTML event coordinates (elem.offsetParent-relative) - convert it to parent.content-relative
var parent = this.getParent();
if (parent && this.elem) {
var cpos = parent.offsetToContent(this.elem.offsetParent, {x: rect.x, y: rect.y});
rect.x = cpos.x;
rect.y = cpos.y;
}
RULE('setWidgetDimensions', base, null, null, rect, this.board.sessionCache);
end
// VC04: METHOD('getBoxPos', function() {
virtual method getBasePos()
var v=SPLIT(base.pos), gs=this.board.gridSize;
return {x:MAX(ROUND(v[0]||0, gs), 0), y:MAX(ROUND(v[1]||0, gs), 0)}
end
// VC04: METHOD('getBoxSize', function() {
virtual method getBaseSize()
var v=SPLIT(base.size), gs=this.board.gridSize;
return {w:MAX(ROUND(v[0]||320, gs), 8), h:MAX(ROUND(v[1]||240, gs), 8)}
end
virtual method getBaseRect()
var pos = this.getBasePos();
var size = this.getBaseSize();
var rect = {x: pos.x, y: pos.y, w: size.w, h: size.h};
return rect;
end
virtual method getBaseZOrder()
// NOTE: Implement and get rid of the 'undefined' option
return (base.z === undefined) ? 0 : base.z;
end
/////////////////////////////////////////////////////////////////////////////
// Widget methods
<@method name="createHtmlElement">
Creates a new element in the owner document of this box
The tag name of the new element
The CSS class name to assign to the new element
The parent element under which to append the new element
The new element
// VC04: METHOD('createElement', function(tagName, className, parentElement) {
virtual method createHtmlElement(tagName, className, id, parentElement)
var elem = this.doc.createElement(tagName);
if (className) elem.className = className;
if (parentElement) parentElement.appendChild(elem);
if (id) elem.id = id;
return elem;
end
// returns rectangle to use when repainting the object
// (usually either calculated from 'base' or taken asked from parent Widget)
virtual method getRepaintRect()
return {x: 0, y: 0, w: 0, h: 0};
end
<@method name="fitContents">
Resizes the box to fit its contents
// VC04: METHOD('fitContents', function() {
virtual method fitContents()
// override
end
/*
<@method name="fitWindow">
Resizes the box to fit the window
// NOTE: Implement
// VC04: METHOD('fitWindow', function() {
virtual method fitWindow()
var rule=this.rule, pos=rule.@getBoxPos(), size=rule.@getBoxSize(), gs=this.elem.gs;
var W = (this.board.gridObj.offsetWidth || 200) - 2*gs;
rule.setProperty('@box_pos', gs+' '+pos.y); // rule.setAttr('box_pos', gs+' '+pos.y);
rule.setProperty('@box_size', W+' '+size.h); // rule.setAttr('box_size', W+' '+size.h);
end
*/
<@method name="getItem">
Gets a specified box item (field)
The requested item name
// VC04: METHOD('getItem', function(name) {
virtual method getItem(name)
// override //NOTE: see if this should be part of Interactor
end
<@method name="clearContents">
Clears the contents of this box
// VC04: METHOD('clearContents', function() {
virtual method clearContents()
// override
end
<@method name="repaintContents">
Repaints the contents of this box
// VC04: METHOD('repaintContents', function() {
virtual method repaintContents(attr)
// override
end
<@method name="reselectContents">
Reselects the box contents after the contents are scrolled
virtual method reselectContents()
var sel = this.board.selection;
if (!sel || sel.size==0) return;
var item = sel.getItem(0);
if (!this.elem.contains(item)) return;
if (this.scrollTimer) clearTimeout(this.scrollTimer);
this.scrollTimer = setTimeout(function () { sel.adjustSelection(); }, 10);
end
<@method name="layoutContents">
Rearranges the contents of this widget
virtual method layoutContents(focusWidget, operation)
return false;
end
<@method name="resizeRepeater">
Resizes the contents repeater block
// VC04: METHOD('resizeRepeater', function() {
virtual method resizeRepeater()
// override
end
virtual method applyFrameStyle()
// override
end
// Returns content rect in client (this.elem-relative) coordinates
virtual method getContentRect()
var elem = this.elem; if (!elem) return {x:0, y:0, w:0, h:0};
return {x: 0, y: 0, w: elem.clientWidth, h: elem.clientHeight };
end
// Returns size object with current content scroll ratios
virtual method getContentScroll()
var elem = this.elem; if (!elem) return {w: 0, h: 0};
return {w: elem.scrollLeft, h: elem.scrollTop};
end
// Returns Widget content area rect in absolute (EDITBOX-relative) coordinates
virtual method getAbsoluteContentRect()
var rect = this.getContentRect();
var elem = this.elem; if (!elem) return rect;
var opos = {x: rect.x, y: rect.y};
var apos = this.board.offsetToAbsolute(elem, opos);
rect.x = apos.x;
rect.y = apos.y;
return rect;
end
// Converts offset coordinates (coords relative to elem.offsetParent, like event.offsetX/Y) to content-relative (relative to widget.contents)
virtual method offsetToContent(elem, pos)
if (!elem || !this.elem || (elem == this.elem)) return pos;
return this.board.offsetToClient(this.elem, elem, pos);
end
virtual method adjustDndArrows(clientX, clientY, currentElement, checkParent)
var data = {
oneArrowVisible: false,
twoArrowVisible: false,
dropObjVisible: false,
newIndex: undefined,
newOffX: 0,
newParent: undefined
};
return data;
end
virtual method adjustParentArrows(currentElement)
var data = {
oneArrowVisible: false,
twoArrowVisible: false,
dropObjVisible: false,
formObjVisible: false,
newIndex: undefined,
newOffX: 0,
newOffY: 0,
newParent: undefined,
cellObject: undefined,
dropObjLeft: 0,
dropObjTop: 0,
dropObjWidth: 0,
dropObjHeight: 0,
left: 0,
top: 0,
formObjLeft: 0,
formObjTop: 0,
formObjWidth: 0,
formObjHeight: 0,
formObjRow: -1,
formObjCol: -1
};
try {
var r = this.getAbsoluteContentRect();
if (base.arrows) {
var left = base.arrows[this.board.getWidget(currentElement).base.index].left;
data.top = r.y - this.arrowImageTopShift;
data.left = r.x + left;
data.newOffX = left;
}
data.dropObjLeft = r.x + this.getDropLeftShift();
data.dropObjTop = r.y;
data.dropObjWidth = r.w;
data.dropObjHeight = r.h;
}
catch(ex) {}
return data;
end
virtual method getArrowedWidgetFromPoint(point)
var elems = [];
var styles = [];
var widget = this;
var board = this.board;
while(widget) {
var st = widget.elem.style;
elems.push(st);
styles.push(st.visibility);
st.visibility = 'hidden';
var prev = widget;
widget = board.getWidgetFromPoint(point);
if (widget && widget.id == prev.id) break;
}
for (var len = elems.length, i = len - 1; i>= 0; i--)
elems[i].visibility = styles[i];
return widget;
end
virtual method getDropLeftShift()
return 0;
end
/*
* Returns contents top gap.
*/
virtual method getContentsTopGap()
return 0;
end
/*
* Returns contents left gap.
*/
virtual method getContentsLeftGap()
return 0;
end
/*
* Returns ~true if Point (x,y) is inside the wiget's Rectangle borders.
* else - returns ~false
*/
virtual method isAtPos(x, y)
var r = this.getAbsoluteContentRect();
if (r) {
if (x > r.x && x < (r.x + r.w) && y > r.y && y < (r.y + r.h))
return true;
}
return false;
end
virtual method checkOrganizer()
//override
end