|
/*
|
|
* Copyright (C) 2010 Emweb bvba, Kessel-Lo, Belgium.
|
|
*
|
|
* See the LICENSE file for terms of use.
|
|
*/
|
|
|
|
/* Note: this is at the same time valid JavaScript and C++. */
|
|
|
|
WT_DECLARE_WT_MEMBER
|
|
(1, JavaScriptConstructor, "WTreeView",
|
|
function(APP, el, contentsContainer, headerContainer, rowHeaderCount) {
|
|
jQuery.data(el, 'obj', this);
|
|
|
|
var contents = contentsContainer.firstChild;
|
|
var headers = headerContainer.firstChild;
|
|
|
|
var self = this;
|
|
var WT = APP.WT;
|
|
|
|
/** @const */ var EnsureVisible = 0;
|
|
/** @const */ var PositionAtTop = 1;
|
|
/** @const */ var PositionAtBottom = 2;
|
|
/** @const */ var PositionAtCenter = 3;
|
|
|
|
function getItem(event) {
|
|
var columnId = -1, nodeId = null, selected = false,
|
|
drop = false, ele = null;
|
|
|
|
var t = WT.target(event);
|
|
|
|
while (t) {
|
|
if (t.className.indexOf('c1 rh') == 0) {
|
|
if (columnId == -1)
|
|
columnId = 0;
|
|
} else if (t.className.indexOf('Wt-tv-c') == 0) {
|
|
if (t.className.indexOf('Wt-tv-c') == 0)
|
|
columnId = t.className.split(' ')[0].substring(7) * 1;
|
|
else if (columnId == -1)
|
|
columnId = 0;
|
|
if (t.getAttribute('drop') === 'true')
|
|
drop = true;
|
|
ele = t;
|
|
} else if (t.className == 'Wt-tv-node') {
|
|
nodeId = t.id;
|
|
break;
|
|
}
|
|
if (t.className === 'Wt-selected')
|
|
selected = true;
|
|
t = t.parentNode;
|
|
if (WT.hasTag(t, 'BODY'))
|
|
break;
|
|
}
|
|
|
|
return { columnId: columnId, nodeId: nodeId, selected: selected,
|
|
drop: drop, el: ele };
|
|
};
|
|
|
|
this.click = function(obj, event) {
|
|
var item = getItem(event);
|
|
if (item.columnId != -1) {
|
|
APP.emit(el, { name: 'itemEvent', eventObject: obj, event: event },
|
|
item.nodeId, item.columnId, 'clicked', '', '');
|
|
}
|
|
};
|
|
|
|
this.dblClick = function(obj, event) {
|
|
var item = getItem(event);
|
|
if (item.columnId != -1) {
|
|
APP.emit(el, { name: 'itemEvent', eventObject: obj, event: event },
|
|
item.nodeId, item.columnId, 'dblclicked', '', '');
|
|
}
|
|
};
|
|
|
|
this.mouseDown = function(obj, event) {
|
|
WT.capture(null);
|
|
var item = getItem(event);
|
|
if (item.columnId != -1) {
|
|
APP.emit(el, { name: 'itemEvent', eventObject: obj, event: event },
|
|
item.nodeId, item.columnId, 'mousedown', '', '');
|
|
if (el.getAttribute('drag') === 'true' && item.selected)
|
|
APP._p_.dragStart(el, event);
|
|
}
|
|
};
|
|
|
|
this.mouseUp = function(obj, event) {
|
|
var item = getItem(event);
|
|
if (item.columnId != -1) {
|
|
APP.emit(el, { name: 'itemEvent', eventObject: obj, event: event },
|
|
item.nodeId, item.columnId, 'mouseup', '', '');
|
|
}
|
|
};
|
|
|
|
this.resizeHandleMDown = function(obj, event) {
|
|
var parent = obj.parentNode.parentNode,
|
|
c = parent.className.split(' ')[0];
|
|
|
|
if (c) {
|
|
var r = WT.getCssRule('#' + el.id + ' .' + c),
|
|
cw = WT.pxself(r, 'width'),
|
|
minDelta = -cw,
|
|
maxDelta = 10000,
|
|
rtl = $(document.body).hasClass('Wt-rtl');
|
|
|
|
if (rtl) {
|
|
var tmp = minDelta;
|
|
minDelta = -maxDelta;
|
|
maxDelta = -tmp;
|
|
}
|
|
|
|
new WT.SizeHandle(WT, 'h', obj.offsetWidth, el.firstChild.offsetHeight,
|
|
minDelta, maxDelta, 'Wt-hsh',
|
|
function (delta) {
|
|
var newWidth = cw + (rtl ? -delta : delta),
|
|
columnId = c.substring(7) * 1;
|
|
r.style.width = newWidth + 'px';
|
|
self.adjustColumns();
|
|
APP.emit(el, 'columnResized', columnId,
|
|
parseInt(newWidth));
|
|
}, obj, el, event, -2, -1);
|
|
}
|
|
};
|
|
|
|
/*
|
|
* this adjusts invariants that take into account column resizes
|
|
*
|
|
* c0w is set as soon as possible.
|
|
*
|
|
* if (!column1 fixed):
|
|
* 1) width('Wt-headerdiv') = sum(column widths)
|
|
* 2) width('float: right') = sum(column(-1) widths)
|
|
* 3) width(table parent) = width('Wt-headerdiv')
|
|
* else
|
|
* 4) width('Wt-rowc') = sum(column(-1) widths)
|
|
*/
|
|
var adjustScheduled = false;
|
|
|
|
/*
|
|
* sometimes autoJavaScript() will run before adjustColumns()
|
|
* we should schedule the autoJavaScript() after first calling adjustColumns(). --DQ Qin
|
|
*/
|
|
var adjustColumnsDone = false;
|
|
var adjustColumnsFirstTime = true;
|
|
|
|
this.adjustColumns = function() {
|
|
if (adjustScheduled)
|
|
return;
|
|
|
|
adjustScheduled = true;
|
|
|
|
setTimeout(function() {
|
|
adjustScheduled = false;
|
|
|
|
var t = contents.firstChild, // table parent
|
|
hc = headers.firstChild, // Wt-tv-row
|
|
allw_1=0, allw=0,
|
|
c0id = headers.lastChild.className.split(' ')[0],
|
|
c0r = WT.getCssRule('#' + el.id + ' .' + c0id);
|
|
|
|
if (rowHeaderCount)
|
|
hc = hc.firstChild; // Wt-tv-rowc
|
|
|
|
if (WT.isHidden(el) || (headers.offsetWidth - hc.offsetWidth < 8))
|
|
return;
|
|
|
|
for (var i=0, length=hc.childNodes.length; i < length; ++i) {
|
|
if (hc.childNodes[i].className) { // IE may have only a text node
|
|
var cl = hc.childNodes[i].className.split(' ')[0],
|
|
r = WT.getCssRule('#' + el.id + ' .' + cl);
|
|
|
|
if (r.style.display == 'none')
|
|
continue;
|
|
|
|
// 7 = 2 * 3px (padding) + 1px border
|
|
allw_1 += WT.pxself(r, 'width') + 7;
|
|
}
|
|
}
|
|
|
|
if (!rowHeaderCount)
|
|
if (!c0r.style.width) // first resize and c0 width not set
|
|
c0r.style.width = (headers.offsetWidth - hc.offsetWidth - 8) + 'px';
|
|
else
|
|
$(el).find('.Wt-headerdiv .' + c0id).css('width', c0r.style.width);
|
|
|
|
allw = allw_1 + WT.pxself(c0r, 'width') + (WT.isIE6 ? 10 : 8);
|
|
|
|
if (!rowHeaderCount) {
|
|
headers.style.width = t.style.width = allw + 'px';
|
|
hc.style.width = allw_1 + 'px';
|
|
} else {
|
|
var r = WT.getCssRule('#' + el.id + ' .Wt-tv-rowc');
|
|
r.style.width = allw_1 + 'px';
|
|
|
|
//.Wt-tv-row should also be changed, otherwise right float divs will be "hidden" --DQ Qin
|
|
var r1 = WT.getCssRule('#' + el.id + ' .Wt-tv-row');
|
|
r1.style.width = allw_1 + 'px';
|
|
|
|
if (WT.isIE) {
|
|
setTimeout(function() {
|
|
$(el).find('.Wt-tv-rowc')
|
|
.css('width', allw_1 + 'px')
|
|
.css('width', '');
|
|
$(el).find('.Wt-tv-row')
|
|
.css('width', allw_1 + 'px')
|
|
.css('width', '');
|
|
}, 0);
|
|
}
|
|
|
|
el.changed = true;
|
|
}
|
|
|
|
// schedule autoJavaScript() at the end of adjustColumns() -- DQ Qin
|
|
if (adjustColumnsFirstTime) {
|
|
self.autoJavaScript();
|
|
adjustColumnsFirstTime = false;
|
|
}
|
|
adjustColumnsDone = true;
|
|
}, 0);
|
|
};
|
|
|
|
var dropEl = null;
|
|
|
|
el.handleDragDrop=function(action, object, event, sourceId, mimeType) {
|
|
if (dropEl) {
|
|
dropEl.className = dropEl.classNameOrig;
|
|
dropEl = null;
|
|
}
|
|
|
|
if (action=='end')
|
|
return;
|
|
|
|
var item = getItem(event);
|
|
|
|
if (!item.selected && item.drop && item.columnId != -1) {
|
|
if (action=='drop') {
|
|
APP.emit(el, { name: 'itemEvent', eventObject: object, event: event },
|
|
item.nodeId, item.columnId, 'drop', sourceId, mimeType);
|
|
} else {
|
|
object.className = 'Wt-valid-drop';
|
|
dropEl = item.el;
|
|
dropEl.classNameOrig = dropEl.className;
|
|
dropEl.className = dropEl.className + ' Wt-drop-site';
|
|
}
|
|
} else {
|
|
object.className = '';
|
|
}
|
|
};
|
|
|
|
/*
|
|
* This adjusts invariants that depend on the size of the whole
|
|
* treeview:
|
|
*
|
|
* - changes to the total width (tw inc. affected by scrollbar)
|
|
* - when column1 is fixed:
|
|
* * .row width
|
|
* * table parent width
|
|
*/
|
|
|
|
this.autoJavaScript = function() {
|
|
if (el.parentNode == null) {
|
|
el = contentsContainer = headerContainer = contents = headers = null;
|
|
this.autoJavaScript = function() { };
|
|
return;
|
|
}
|
|
|
|
if (WT.isHidden(el))
|
|
return;
|
|
|
|
if (!adjustColumnsDone) //adjustColumns() has never run. --DQ Qin
|
|
return;
|
|
|
|
var $el=$(el),
|
|
c0id, c0r, c0w = null;
|
|
|
|
var tw = WT.pxself(el, 'width');
|
|
|
|
if (tw == 0)
|
|
tw = el.clientWidth;
|
|
else if (WT.boxSizing(el)) {
|
|
tw -= WT.px(el, 'borderLeftWidth');
|
|
tw -= WT.px(el, 'borderRightWidth');
|
|
}
|
|
|
|
var scrollwidth = contentsContainer.offsetWidth
|
|
- contentsContainer.clientWidth;
|
|
|
|
tw -= scrollwidth;
|
|
|
|
if ($el.hasClass('column1')) {
|
|
c0id = $el.find('.Wt-headerdiv').get(0)
|
|
.lastChild.className.split(' ')[0];
|
|
c0r = WT.getCssRule('#' + el.id + ' .' + c0id);
|
|
c0w = WT.pxself(c0r, 'width');
|
|
|
|
}
|
|
|
|
// XXX: IE's incremental rendering foobars completely
|
|
if ((!WT.isIE || tw > 100)
|
|
&& (tw != contentsContainer.tw ||
|
|
c0w != contentsContainer.c0w ||
|
|
el.changed)) {
|
|
var adjustColumns = !el.changed;
|
|
|
|
contentsContainer.tw = tw;
|
|
contentsContainer.c0w = c0w;
|
|
|
|
c0id = $el.find('.Wt-headerdiv').get(0)
|
|
.lastChild.className.split(' ')[0];
|
|
c0r = WT.getCssRule('#' + el.id + ' .' + c0id);
|
|
|
|
var table = contents.firstChild,
|
|
r = WT.getCssRule('#' + el.id + ' .cwidth'),
|
|
contentstoo = (r.style.width == table.offsetWidth + 'px'),
|
|
hc = headers.firstChild;
|
|
|
|
r.style.width = tw + 'px';
|
|
|
|
contentsContainer.style.width = (tw + scrollwidth) + 'px';
|
|
|
|
// IE moves the scrollbar left in rtl mode.
|
|
if (!WT.isIE)
|
|
headerContainer.style.marginRight = scrollwidth + 'px';
|
|
|
|
if (c0w != null) {
|
|
var w = tw - c0w - (WT.isIE6 ? 10 : 8);
|
|
|
|
if (w > 0) {
|
|
var w2
|
|
= Math.min(w, WT.pxself
|
|
(WT.getCssRule('#' + el.id + ' .Wt-tv-row'),'width'));
|
|
tw -= (w - w2);
|
|
|
|
headers.style.width=tw + 'px';
|
|
table.style.width=tw + 'px';
|
|
|
|
/* This is really slow in FF, slower than the jquery equivalent */
|
|
WT.getCssRule('#' + el.id + ' .Wt-tv-row').style.width = w2 + 'px';
|
|
|
|
if (WT.isIE)
|
|
setTimeout(function() {
|
|
$el.find(' .Wt-tv-row')
|
|
.css('width', w2 + 'px')
|
|
.css('width', '');
|
|
}, 0);
|
|
}
|
|
} else {
|
|
if (contentstoo) {
|
|
headers.style.width=r.style.width;
|
|
table.style.width=r.style.width;
|
|
} else
|
|
headers.style.width = table.offsetWidth + 'px';
|
|
}
|
|
|
|
if (!rowHeaderCount && (table.offsetWidth - hc.offsetWidth >= 8))
|
|
c0r.style.width = (table.offsetWidth - hc.offsetWidth - 8) + 'px';
|
|
|
|
el.changed = false;
|
|
|
|
if (adjustColumns && !adjustColumnsFirstTime /* && WT.isIE */)
|
|
self.adjustColumns();
|
|
}
|
|
};
|
|
|
|
this.scrollTo = function(x, y, rowHeight, hint) {
|
|
if (y != -1) {
|
|
y *= rowHeight;
|
|
var top = contentsContainer.scrollTop,
|
|
height = contentsContainer.clientHeight;
|
|
if (hint == EnsureVisible) {
|
|
if (top + height < y)
|
|
hint = PositionAtTop;
|
|
else if (y < top)
|
|
hint = PositionAtBottom;
|
|
}
|
|
|
|
switch (hint) {
|
|
case PositionAtTop:
|
|
contentsContainer.scrollTop = y; break;
|
|
case PositionAtBottom:
|
|
contentsContainer.scrollTop = y - (height - rowHeight); break;
|
|
case PositionAtCenter:
|
|
contentsContainer.scrollTop = y - (height - rowHeight)/2; break;
|
|
}
|
|
|
|
window.fakeEvent = {object: contentsContainer};
|
|
contentsContainer.onscroll(window.fakeEvent);
|
|
window.fakeEvent = null;
|
|
}
|
|
};
|
|
|
|
self.adjustColumns();
|
|
|
|
});
|