зеркало из https://github.com/mozilla/pjs.git
1072 строки
38 KiB
XML
1072 строки
38 KiB
XML
<?xml version="1.0"?>
|
|
|
|
<bindings id="treeBindings"
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
|
|
|
<binding id="tree-base">
|
|
<resources>
|
|
<stylesheet src="chrome://global/skin/tree.css"/>
|
|
</resources>
|
|
</binding>
|
|
|
|
<binding id="tree" extends="chrome://global/content/bindings/tree.xml#tree-base">
|
|
<content>
|
|
<children includes="treecols"/>
|
|
<xul:treerows class="tree-rows" flex="1">
|
|
<children/>
|
|
</xul:treerows>
|
|
</content>
|
|
|
|
<implementation implements="nsIAccessibleProvider">
|
|
|
|
<!-- ///////////////// nsIAccessibleProvider ///////////////// -->
|
|
|
|
<property name="accessible">
|
|
<getter>
|
|
<![CDATA[
|
|
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
|
|
return accService.createXULTreeAccessible(this);
|
|
]]>
|
|
</getter>
|
|
</property>
|
|
|
|
<property name="treeBoxObject"
|
|
onget="return this.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);"
|
|
readonly="true"/>
|
|
<property name="view"
|
|
onget="return this.treeBoxObject.view;"
|
|
onset="return this.treeBoxObject.view=val;"/>
|
|
# contentView is obsolete (see bug 202391)
|
|
<property name="contentView"
|
|
onget="return this.treeBoxObject.view; /*.QueryInterface(Components.interfaces.nsITreeContentView)*/"
|
|
readonly="true"/>
|
|
# builderView is obsolete (see bug 202393)
|
|
<property name="builderView"
|
|
onget="return this.treeBoxObject.view; /*.QueryInterface(Components.interfaces.nsIXULTreeBuilder)*/"
|
|
readonly="true"/>
|
|
<property name="currentIndex"
|
|
onget="return this.treeBoxObject.selection.currentIndex;"
|
|
onset="return this.treeBoxObject.selection.currentIndex=val;"/>
|
|
<field name="pageUpOrDownMovesSelection">
|
|
#ifdef XP_MACOSX
|
|
false
|
|
#else
|
|
true
|
|
#endif
|
|
</field>
|
|
<field name="selectionHead">
|
|
-1
|
|
</field>
|
|
<field name="selectionTail">
|
|
-1
|
|
</field>
|
|
<property name="enableColumnDrag"
|
|
onget="return this.hasAttribute('enableColumnDrag');"
|
|
onset="if (val) this.setAttribute('enableColumnDrag', 'true');
|
|
else this.removeAttribute('enableColumnDrag'); return val;"/>
|
|
|
|
<property name="firstOrdinalColumn">
|
|
<getter><![CDATA[
|
|
var cols = this.firstChild;
|
|
while (cols && cols.localName != "treecols")
|
|
cols = cols.nextSibling;
|
|
|
|
if (cols)
|
|
return cols.boxObject.firstChild;
|
|
else
|
|
return null;
|
|
]]></getter>
|
|
</property>
|
|
|
|
<property name="disableKeyNavigation"
|
|
onget="return this.hasAttribute('disableKeyNavigation');"
|
|
onset="if (val) this.setAttribute('disableKeyNavigation', 'true');
|
|
else this.removeAttribute('disableKeyNavigation'); return val;"/>
|
|
|
|
<property name="_selectDelay"
|
|
onset="this.setAttribute('_selectDelay', val);"
|
|
onget="return this.getAttribute('_selectDelay') || 50;"/>
|
|
<field name="_columnsDirty">true</field>
|
|
<field name="_lastKeyTime">0</field>
|
|
<field name="_incrementalString">""</field>
|
|
|
|
<method name="_ensureColumnOrder">
|
|
<body><![CDATA[
|
|
if (this._columnsDirty) {
|
|
// update the ordinal position of each column to assure that it is
|
|
// an odd number and 2 positions above it's next sibling
|
|
var col = this.firstOrdinalColumn;
|
|
var cols = [];
|
|
while (col) {
|
|
if (col.localName == "treecol" && col.parentNode.parentNode == this)
|
|
cols[cols.length] = col;
|
|
col = col.boxObject.nextSibling;
|
|
}
|
|
var i;
|
|
for (i = 0; i < cols.length; ++i)
|
|
cols[i].setAttribute("ordinal", (i*2)+1);
|
|
|
|
// update the ordinal positions of splitters to even numbers, so that
|
|
// they are in between columns
|
|
var splitters = this.getElementsByTagName("splitter");
|
|
for (i = 0; i < splitters.length; ++i)
|
|
splitters[i].setAttribute("ordinal", (i+1)*2);
|
|
|
|
this._columnsDirty = false;
|
|
}
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="_reorderColumn">
|
|
<parameter name="aColMove"/>
|
|
<parameter name="aColBefore"/>
|
|
<parameter name="aBefore"/>
|
|
<body><![CDATA[
|
|
this._ensureColumnOrder();
|
|
|
|
var cols = [];
|
|
var col;
|
|
if (aColBefore.ordinal < aColMove.ordinal) {
|
|
col = aColBefore;
|
|
while (col) {
|
|
if (col.localName == "treecol")
|
|
cols.push(col);
|
|
col = col.boxObject.nextSibling;
|
|
if (col == aColMove)
|
|
break;
|
|
}
|
|
|
|
aColMove.ordinal = aColBefore.ordinal;
|
|
var i;
|
|
for (i = 0; i < cols.length; ++i)
|
|
cols[i].ordinal += 2;
|
|
} else {
|
|
col = aColMove.boxObject.nextSibling;
|
|
while (col) {
|
|
if (col.localName == "treecol")
|
|
cols.push(col);
|
|
col = col.boxObject.nextSibling;
|
|
if (col == aColBefore && aBefore)
|
|
break;
|
|
}
|
|
|
|
aColMove.ordinal = aBefore ? aColBefore.ordinal-2 : aColBefore.ordinal;
|
|
|
|
for (i = 0; i < cols.length; ++i)
|
|
cols[i].ordinal -= 2;
|
|
}
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="_getColumnAtX">
|
|
<parameter name="aX"/>
|
|
<parameter name="aThresh"/>
|
|
<parameter name="aPos"/>
|
|
<body><![CDATA[
|
|
if (aPos) aPos.value = "before";
|
|
|
|
var col = this.firstOrdinalColumn;
|
|
var lastCol = null;
|
|
var currentX = this.boxObject.x;
|
|
while (col) {
|
|
if (col.localName == "treecol" && col.parentNode.parentNode == this) {
|
|
var cw = col.boxObject.width;
|
|
if (cw > 0) {
|
|
currentX += cw;
|
|
if (currentX - (cw*aThresh) > aX)
|
|
return col;
|
|
}
|
|
lastCol = col;
|
|
}
|
|
col = col.boxObject.nextSibling;
|
|
}
|
|
|
|
if (aPos) aPos.value = "after";
|
|
return lastCol;
|
|
]]></body>
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="DOMMouseScroll" phase="capturing">
|
|
<![CDATA[
|
|
var rows = event.detail;
|
|
if (rows == NSUIEvent.SCROLL_PAGE_UP)
|
|
this.treeBoxObject.scrollByPages(-1);
|
|
else if (rows == NSUIEvent.SCROLL_PAGE_DOWN)
|
|
this.treeBoxObject.scrollByPages(1);
|
|
else
|
|
this.treeBoxObject.scrollByLines(rows);
|
|
]]>
|
|
</handler>
|
|
<handler event="focus" action="this.treeBoxObject.focused = true;"/>
|
|
<handler event="blur" action="this.treeBoxObject.focused = false;"/>
|
|
|
|
<handler event="dragenter" action="this.treeBoxObject.onDragEnter(event);"/>
|
|
<handler event="dragexit" action="this.treeBoxObject.onDragExit(event);"/>
|
|
<handler event="dragover" action="this.treeBoxObject.onDragOver(event);"/>
|
|
<handler event="dragdrop" action="this.treeBoxObject.onDragDrop(event);"/>
|
|
|
|
<handler event="keypress" keycode="vk_enter">
|
|
<![CDATA[
|
|
if (this.currentIndex == -1)
|
|
return;
|
|
if (this.treeBoxObject.view.isContainer(this.currentIndex))
|
|
this.treeBoxObject.view.toggleOpenState(this.currentIndex);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_return">
|
|
<![CDATA[
|
|
if (this.currentIndex == -1)
|
|
return;
|
|
if (this.treeBoxObject.view.isContainer(this.currentIndex))
|
|
this.treeBoxObject.view.toggleOpenState(this.currentIndex);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_left">
|
|
<![CDATA[
|
|
if (this.currentIndex == -1)
|
|
return;
|
|
if (this.treeBoxObject.view.isContainer(this.currentIndex) &&
|
|
this.treeBoxObject.view.isContainerOpen(this.currentIndex)) {
|
|
this.treeBoxObject.view.toggleOpenState(this.currentIndex);
|
|
}
|
|
else {
|
|
var parentIndex = this.treeBoxObject.view.getParentIndex(this.currentIndex);
|
|
if (parentIndex >= 0) {
|
|
this.treeBoxObject.selection.select(parentIndex);
|
|
this.treeBoxObject.ensureRowIsVisible(parentIndex);
|
|
}
|
|
}
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_right">
|
|
<![CDATA[
|
|
if (this.currentIndex == -1)
|
|
return;
|
|
if (this.treeBoxObject.view.isContainer(this.currentIndex)) {
|
|
if (!this.treeBoxObject.view.isContainerOpen(this.currentIndex))
|
|
this.treeBoxObject.view.toggleOpenState(this.currentIndex);
|
|
}
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_up">
|
|
<![CDATA[
|
|
var c = this.currentIndex;
|
|
if (c == -1 || c == 0)
|
|
return;
|
|
this.selectionHead = -1;
|
|
this.selectionTail = -1;
|
|
this.treeBoxObject.selection.timedSelect(c-1, this._selectDelay);
|
|
this.treeBoxObject.ensureRowIsVisible(c-1);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_down">
|
|
<![CDATA[
|
|
var c = this.currentIndex;
|
|
try { if (c+1 == this.treeBoxObject.view.rowCount)
|
|
return;
|
|
} catch (e) {}
|
|
this.selectionHead = -1;
|
|
this.selectionTail = -1;
|
|
this.treeBoxObject.selection.timedSelect(c+1, this._selectDelay);
|
|
this.treeBoxObject.ensureRowIsVisible(c+1);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_up" modifiers="shift">
|
|
<![CDATA[
|
|
if (this.treeBoxObject.selection.single)
|
|
return;
|
|
var c = this.currentIndex;
|
|
if (c == -1 || c == 0)
|
|
return;
|
|
if (c == this.selectionTail) {
|
|
if (this.selectionHead < this.selectionTail) {
|
|
this.treeBoxObject.selection.toggleSelect(c);
|
|
this.currentIndex = c - 1;
|
|
}
|
|
else {
|
|
this.treeBoxObject.selection.toggleSelect(c - 1);
|
|
}
|
|
}
|
|
else {
|
|
this.treeBoxObject.selection.clearSelection();
|
|
this.selectionHead = c;
|
|
this.treeBoxObject.selection.rangedSelect(c, c - 1, true);
|
|
}
|
|
this.selectionTail = c - 1;
|
|
this.treeBoxObject.ensureRowIsVisible(c - 1);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_down" modifiers="shift">
|
|
<![CDATA[
|
|
if (this.treeBoxObject.selection.single)
|
|
return;
|
|
var c = this.currentIndex;
|
|
try { if (c+1 == this.treeBoxObject.view.rowCount)
|
|
return;
|
|
} catch (e) {}
|
|
if (c == this.selectionTail) {
|
|
if (this.selectionHead > this.selectionTail) {
|
|
this.treeBoxObject.selection.toggleSelect(c);
|
|
this.currentIndex = c + 1;
|
|
}
|
|
else
|
|
this.treeBoxObject.selection.toggleSelect(c + 1);
|
|
}
|
|
else {
|
|
this.treeBoxObject.selection.clearSelection();
|
|
this.selectionHead = c;
|
|
this.treeBoxObject.selection.rangedSelect(c, c + 1, true);
|
|
}
|
|
this.selectionTail = c + 1;
|
|
this.treeBoxObject.ensureRowIsVisible(c + 1);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_up" modifiers="control">
|
|
<![CDATA[
|
|
var c = this.currentIndex;
|
|
if (c == -1 || c == 0)
|
|
return;
|
|
this.currentIndex = c-1;
|
|
this.treeBoxObject.ensureRowIsVisible(c-1);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_down" modifiers="control">
|
|
<![CDATA[
|
|
var c = this.currentIndex;
|
|
try { if (c+1 == this.treeBoxObject.view.rowCount)
|
|
return;
|
|
} catch (e) {}
|
|
this.currentIndex = c+1;
|
|
this.treeBoxObject.ensureRowIsVisible(c+1);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_page_up">
|
|
<![CDATA[
|
|
if (! this.pageUpOrDownMovesSelection) {
|
|
this.treeBoxObject.scrollByPages(-1);
|
|
return;
|
|
}
|
|
var c = this.currentIndex;
|
|
if (c == 0)
|
|
return;
|
|
this.selectionHead = -1;
|
|
this.selectionTail = -1;
|
|
var f = this.treeBoxObject.getFirstVisibleRow();
|
|
var i = 0;
|
|
if (f > 0) {
|
|
var p = this.treeBoxObject.getPageCount();
|
|
if (f - p >= 0)
|
|
i = c - p;
|
|
else
|
|
i = c - f;
|
|
this.treeBoxObject.scrollByPages(-1);
|
|
}
|
|
this.treeBoxObject.selection.timedSelect(i, this._selectDelay);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_page_down">
|
|
<![CDATA[
|
|
if (! this.pageUpOrDownMovesSelection) {
|
|
this.treeBoxObject.scrollByPages(1);
|
|
return;
|
|
}
|
|
var c = this.currentIndex;
|
|
var l = this.treeBoxObject.view.rowCount - 1;
|
|
if (c == l)
|
|
return;
|
|
this.selectionHead = -1;
|
|
this.selectionTail = -1;
|
|
var f = this.treeBoxObject.getFirstVisibleRow();
|
|
var p = this.treeBoxObject.getPageCount();
|
|
var i = l;
|
|
var lastTopRowIndex = l - p;
|
|
if (f <= lastTopRowIndex) {
|
|
if (f + p <= lastTopRowIndex)
|
|
i = c + p;
|
|
else
|
|
i = lastTopRowIndex + c - f + 1;
|
|
this.treeBoxObject.scrollByPages(1);
|
|
}
|
|
this.treeBoxObject.selection.timedSelect(i, this._selectDelay);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_page_up" modifiers="shift">
|
|
<![CDATA[
|
|
if (this.treeBoxObject.selection.single)
|
|
return;
|
|
var c = this.currentIndex;
|
|
if (c == 0)
|
|
return;
|
|
var f = this.treeBoxObject.getFirstVisibleRow();
|
|
var i = 0;
|
|
if (f > 0) {
|
|
var p = this.treeBoxObject.getPageCount();
|
|
if (f - p >= 0)
|
|
i = c - p;
|
|
else
|
|
i = c - f;
|
|
this.treeBoxObject.scrollByPages(-1);
|
|
}
|
|
if (c == this.selectionTail) {
|
|
if (this.selectionHead < this.selectionTail) {
|
|
if (i < this.selectionHead) {
|
|
this.treeBoxObject.selection.clearRange(c, this.selectionHead + 1);
|
|
this.treeBoxObject.selection.rangedSelect(this.selectionHead - 1, i, true);
|
|
}
|
|
else {
|
|
this.treeBoxObject.selection.clearRange(c, i + 1);
|
|
this.currentIndex = i;
|
|
}
|
|
}
|
|
else
|
|
this.treeBoxObject.selection.rangedSelect(c - 1, i, true);
|
|
}
|
|
else {
|
|
this.treeBoxObject.selection.clearSelection();
|
|
this.selectionHead = c;
|
|
this.treeBoxObject.selection.rangedSelect(c, i, true);
|
|
}
|
|
this.selectionTail = i;
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_page_down" modifiers="shift">
|
|
<![CDATA[
|
|
if (this.treeBoxObject.selection.single)
|
|
return;
|
|
var c = this.currentIndex;
|
|
var l = this.treeBoxObject.view.rowCount - 1;
|
|
if (c == l)
|
|
return;
|
|
var f = this.treeBoxObject.getFirstVisibleRow();
|
|
var p = this.treeBoxObject.getPageCount();
|
|
var i = l;
|
|
var lastTopRowIndex = l - p;
|
|
if (f <= lastTopRowIndex) {
|
|
if (f + p <= lastTopRowIndex)
|
|
i = c + p;
|
|
else
|
|
i = lastTopRowIndex + c - f + 1;
|
|
this.treeBoxObject.scrollByPages(1);
|
|
}
|
|
if (c == this.selectionTail) {
|
|
if (this.selectionHead > this.selectionTail) {
|
|
if (i > this.selectionHead) {
|
|
this.treeBoxObject.selection.clearRange(c, this.selectionHead - 1);
|
|
this.treeBoxObject.selection.rangedSelect(this.selectionHead + 1, i, true);
|
|
}
|
|
else {
|
|
this.treeBoxObject.selection.clearRange(c, i - 1);
|
|
this.currentIndex = i;
|
|
}
|
|
}
|
|
else
|
|
this.treeBoxObject.selection.rangedSelect(c + 1, i, true);
|
|
}
|
|
else {
|
|
this.treeBoxObject.selection.clearSelection();
|
|
this.selectionHead = c;
|
|
this.treeBoxObject.selection.rangedSelect(c, i, true);
|
|
}
|
|
this.selectionTail = i;
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_page_up" modifiers="control">
|
|
<![CDATA[
|
|
var c = this.currentIndex;
|
|
if (c == 0)
|
|
return;
|
|
var f = this.treeBoxObject.getFirstVisibleRow();
|
|
var i = 0;
|
|
if (f > 0) {
|
|
var p = this.treeBoxObject.getPageCount();
|
|
if (f - p >= 0)
|
|
i = c - p;
|
|
else
|
|
i = c - f;
|
|
this.treeBoxObject.scrollByPages(-1);
|
|
}
|
|
this.currentIndex = i;
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_page_down" modifiers="control">
|
|
<![CDATA[
|
|
var c = this.currentIndex;
|
|
var l = this.treeBoxObject.view.rowCount - 1;
|
|
if (c == l)
|
|
return;
|
|
var f = this.treeBoxObject.getFirstVisibleRow();
|
|
var p = this.treeBoxObject.getPageCount();
|
|
var i = l;
|
|
var lastTopRowIndex = l - p;
|
|
if (f <= lastTopRowIndex) {
|
|
if (f + p <= lastTopRowIndex)
|
|
i = c + p;
|
|
else
|
|
i = lastTopRowIndex + c - f + 1;
|
|
this.treeBoxObject.scrollByPages(1);
|
|
}
|
|
this.currentIndex = i;
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_home">
|
|
<![CDATA[
|
|
if (this.currentIndex == 0)
|
|
return;
|
|
this.selectionHead = -1;
|
|
this.selectionTail = -1;
|
|
this.treeBoxObject.selection.select(0);
|
|
this.treeBoxObject.ensureRowIsVisible(0);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_end">
|
|
<![CDATA[
|
|
var l = this.treeBoxObject.view.rowCount - 1;
|
|
if (this.currentIndex == l)
|
|
return;
|
|
this.selectionHead = -1;
|
|
this.selectionTail = -1;
|
|
this.treeBoxObject.selection.select(l);
|
|
this.treeBoxObject.ensureRowIsVisible(l);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_home" modifiers="shift">
|
|
<![CDATA[
|
|
if (this.treeBoxObject.selection.single)
|
|
return;
|
|
var c = this.currentIndex;
|
|
if (c == 0)
|
|
return;
|
|
if (c != this.selectionTail) {
|
|
this.treeBoxObject.selection.clearSelection();
|
|
this.selectionHead = c;
|
|
}
|
|
this.treeBoxObject.selection.rangedSelect(c, 0, true);
|
|
this.selectionTail = 0;
|
|
this.treeBoxObject.ensureRowIsVisible(0);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_end" modifiers="shift">
|
|
<![CDATA[
|
|
if (this.treeBoxObject.selection.single)
|
|
return;
|
|
var c = this.currentIndex;
|
|
var l = this.treeBoxObject.view.rowCount - 1;
|
|
if (c == l)
|
|
return;
|
|
if (c != this.selectionTail) {
|
|
this.treeBoxObject.selection.clearSelection();
|
|
this.selectionHead = c;
|
|
}
|
|
this.treeBoxObject.selection.rangedSelect(c, l, true);
|
|
this.selectionTail = l;
|
|
this.treeBoxObject.ensureRowIsVisible(l);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_home" modifiers="control">
|
|
<![CDATA[
|
|
if (this.currentIndex == 0)
|
|
return;
|
|
this.currentIndex = 0;
|
|
this.treeBoxObject.ensureRowIsVisible(0);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="vk_end" modifiers="control">
|
|
<![CDATA[
|
|
var l = this.treeBoxObject.view.rowCount - 1;
|
|
if (this.currentIndex == l)
|
|
return;
|
|
this.currentIndex = l;
|
|
this.treeBoxObject.ensureRowIsVisible(l);
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress">
|
|
<![CDATA[
|
|
var c = this.currentIndex;
|
|
if (event.keyCode == ' '.charCodeAt(0)) {
|
|
if (!this.treeBoxObject.selection.isSelected(c))
|
|
this.treeBoxObject.selection.toggleSelect(c);
|
|
}
|
|
else if (!this.disableKeyNavigation && event.charCode > 0 &&
|
|
!event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) {
|
|
var key = String.fromCharCode(event.charCode);
|
|
key = key.toLowerCase();
|
|
if (event.timeStamp - this._lastKeyTime > 1000)
|
|
this._incrementalString = key;
|
|
else
|
|
this._incrementalString += key;
|
|
this._lastKeyTime = event.timeStamp;
|
|
|
|
var length = this._incrementalString.length;
|
|
var incrementalString = this._incrementalString;
|
|
var charIndex = 1;
|
|
while (charIndex < length && incrementalString[charIndex] == incrementalString[charIndex - 1])
|
|
charIndex++;
|
|
// If all letters in incremental string are same, just try to match the first one
|
|
if (charIndex == length) {
|
|
length = 1;
|
|
incrementalString = incrementalString.substring(0, length);
|
|
}
|
|
|
|
var primarycol = this.treeBoxObject.getKeyColumnIndex();
|
|
var colID = this.treeBoxObject.getColumnID(primarycol);
|
|
var rowCount = this.treeBoxObject.view.rowCount;
|
|
var start = 1;
|
|
|
|
if (length > 1) {
|
|
start = 0;
|
|
if (c < 0)
|
|
c = 0;
|
|
}
|
|
|
|
for (var i = 0; i < rowCount; i++) {
|
|
var l = (i + start + c) % rowCount;
|
|
var cellText = this.treeBoxObject.view.getCellText(l, colID);
|
|
cellText = cellText.substring(0, length).toLowerCase();
|
|
if (cellText == incrementalString) {
|
|
this.selectionHead = -1;
|
|
this.selectionTail = -1;
|
|
this.treeBoxObject.selection.timedSelect(l, this._selectDelay);
|
|
this.treeBoxObject.ensureRowIsVisible(l);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
<binding id="treecols" extends="chrome://global/content/bindings/tree.xml#tree-base">
|
|
<content>
|
|
<children includes="treecol|splitter"/>
|
|
<xul:treecolpicker class="treecol-image" fixed="true" ordinal="2147483647" xbl:inherits="tooltiptext=pickertooltiptext"/>
|
|
</content>
|
|
<implementation implements="nsIAccessibleProvider">
|
|
<property name="accessible">
|
|
<getter>
|
|
<![CDATA[
|
|
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
|
|
return accService.createXULTreeColumnsAccessible(this);
|
|
]]>
|
|
</getter>
|
|
</property>
|
|
</implementation>
|
|
</binding>
|
|
|
|
<binding id="treerows" extends="chrome://global/content/bindings/tree.xml#tree-base">
|
|
<content>
|
|
<xul:hbox flex="1" class="tree-bodybox">
|
|
<children/>
|
|
</xul:hbox>
|
|
<xul:scrollbar height="0" minwidth="0" minheight="0" orient="vertical" class="tree-scrollbar" collapsed="true"/>
|
|
</content>
|
|
<handlers>
|
|
<handler event="underflow">
|
|
<![CDATA[
|
|
document.getAnonymousNodes(this)[1].collapsed = true;
|
|
event.preventBubble();
|
|
]]>
|
|
</handler>
|
|
<handler event="overflow">
|
|
<![CDATA[
|
|
document.getAnonymousNodes(this)[1].collapsed = false;
|
|
event.preventBubble();
|
|
]]>
|
|
</handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
<binding id="treebody" extends="chrome://global/content/bindings/tree.xml#tree-base">
|
|
<implementation>
|
|
<constructor>
|
|
if ("_ensureColumnOrder" in this.parentNode)
|
|
this.parentNode._ensureColumnOrder();
|
|
</constructor>
|
|
|
|
<field name="_lastSelectedRow">
|
|
-1
|
|
</field>
|
|
</implementation>
|
|
<handlers>
|
|
<!-- If there is no modifier key, we select on mousedown, not
|
|
click, so that drags work correctly. -->
|
|
<handler event="mousedown">
|
|
<![CDATA[
|
|
if (((!event.ctrlKey || !this.parentNode.pageUpOrDownMovesSelection) &&
|
|
!event.shiftKey && !event.metaKey) ||
|
|
this.parentNode.treeBoxObject.selection.single) {
|
|
var row = {};
|
|
var col = {};
|
|
var obj = {};
|
|
var b = this.parentNode.treeBoxObject;
|
|
b.getCellAt(event.clientX, event.clientY, row, col, obj);
|
|
|
|
// save off the last selected row
|
|
this._lastSelectedRow = row.value;
|
|
|
|
if (row.value == -1)
|
|
return;
|
|
|
|
if (col.value && obj.value != "twisty") {
|
|
var column = document.getElementById(col.value);
|
|
var cycler = column.hasAttribute('cycler');
|
|
|
|
if (cycler)
|
|
b.view.cycleCell(row.value, col.value);
|
|
else
|
|
if (!b.selection.isSelected(row.value)) {
|
|
b.selection.select(row.value);
|
|
b.ensureRowIsVisible(row.value);
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</handler>
|
|
|
|
<!-- On a click (up+down on the same item), deselect everything
|
|
except this item. -->
|
|
<handler event="click">
|
|
<![CDATA[
|
|
if (event.button != 0) return;
|
|
var row = {};
|
|
var col = {};
|
|
var obj = {};
|
|
var b = this.parentNode.treeBoxObject;
|
|
b.getCellAt(event.clientX, event.clientY, row, col, obj);
|
|
|
|
if (row.value == -1)
|
|
return;
|
|
|
|
if (obj.value == "twisty") {
|
|
if (b.selection.currentIndex >= 0 &&
|
|
b.view.isContainerOpen(row.value)) {
|
|
var parentIndex = b.view.getParentIndex(b.selection.currentIndex);
|
|
while (parentIndex >= 0 && parentIndex != row.value)
|
|
parentIndex = b.view.getParentIndex(parentIndex);
|
|
if (parentIndex == row.value)
|
|
b.selection.select(parentIndex);
|
|
}
|
|
b.view.toggleOpenState(row.value);
|
|
return;
|
|
}
|
|
|
|
if (! this.parentNode.treeBoxObject.selection.single) {
|
|
var augment = event.ctrlKey || event.metaKey;
|
|
if (event.shiftKey) {
|
|
b.selection.rangedSelect(-1, row.value, augment);
|
|
b.ensureRowIsVisible(row.value);
|
|
return;
|
|
}
|
|
if (augment) {
|
|
b.selection.toggleSelect(row.value);
|
|
b.ensureRowIsVisible(row.value);
|
|
b.selection.currentIndex = row.value;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* We want to deselect all the selected items except what was
|
|
clicked, UNLESS it was a right-click. We have to do this
|
|
in click rather than mousedown so that you can drag a
|
|
selected group of items */
|
|
|
|
if (!col.value) return;
|
|
var column = document.getElementById(col.value);
|
|
var cycler = column.hasAttribute('cycler');
|
|
|
|
// if the last row has changed in between the time we
|
|
// mousedown and the time we click, don't fire the select handler.
|
|
// see bug #92366
|
|
if (!cycler && this._lastSelectedRow == row.value) {
|
|
b.selection.select(row.value);
|
|
b.ensureRowIsVisible(row.value);
|
|
}
|
|
]]>
|
|
</handler>
|
|
|
|
<!-- double-click -->
|
|
<handler event="click" clickcount="2">
|
|
<![CDATA[
|
|
var row = {};
|
|
var col = {};
|
|
var obj = {};
|
|
var b = this.parentNode.treeBoxObject;
|
|
b.getCellAt(event.clientX, event.clientY, row, col, obj);
|
|
|
|
if (row.value == -1)
|
|
return;
|
|
|
|
var column = document.getElementById(col.value);
|
|
var cycler = column.hasAttribute('cycler');
|
|
|
|
if (!cycler && obj.value != "twisty" && b.view.isContainer(row.value))
|
|
b.view.toggleOpenState(row.value);
|
|
]]>
|
|
</handler>
|
|
|
|
</handlers>
|
|
</binding>
|
|
|
|
<binding id="treecol-base" extends="chrome://global/content/bindings/tree.xml#tree-base">
|
|
<implementation>
|
|
<constructor>
|
|
this.parentNode.parentNode._columnsDirty = true;
|
|
</constructor>
|
|
|
|
<property name="ordinal">
|
|
<getter><![CDATA[
|
|
var val = this.getAttribute("ordinal");
|
|
return val == "" ? 1 : (val == "0" ? 0 : parseInt(val));
|
|
]]></getter>
|
|
<setter><![CDATA[
|
|
this.setAttribute("ordinal", val);
|
|
]]></setter>
|
|
</property>
|
|
|
|
<property name="_previousVisibleColumn">
|
|
<getter><![CDATA[
|
|
var sib = this.boxObject.previousSibling;
|
|
while (sib) {
|
|
if (sib.localName == "treecol" && sib.boxObject.width > 0 && sib.parentNode == this.parentNode)
|
|
return sib;
|
|
sib = sib.boxObject.previousSibling;
|
|
}
|
|
return null;
|
|
]]></getter>
|
|
</property>
|
|
|
|
<method name="onDragMouseMove">
|
|
<parameter name="aEvent"/>
|
|
<body><![CDATA[
|
|
var col = document.treecolDragging;
|
|
if (!col) return;
|
|
|
|
// determine if we have moved the mouse far enough
|
|
// to initiate a drag
|
|
if (col.mDragGesturing) {
|
|
if (Math.abs(aEvent.clientX - col.mStartDragX) < 5 &&
|
|
Math.abs(aEvent.clientY - col.mStartDragY) < 5) {
|
|
return;
|
|
} else {
|
|
col.mDragGesturing = false;
|
|
col.setAttribute("dragging", "true");
|
|
window.addEventListener("click", col.onDragMouseClick, true);
|
|
}
|
|
}
|
|
|
|
var pos = {};
|
|
var targetCol = col.parentNode.parentNode._getColumnAtX(aEvent.clientX, 0.5, pos);
|
|
|
|
// bail if we haven't mousemoved to a different column
|
|
if (col.mTargetCol == targetCol && col.mTargetDir == pos.value)
|
|
return;
|
|
|
|
var tree = col.parentNode.parentNode;
|
|
var sib;
|
|
if (col.mTargetCol) {
|
|
// remove previous insertbefore/after attributes
|
|
col.mTargetCol.removeAttribute("insertbefore");
|
|
col.mTargetCol.removeAttribute("insertafter");
|
|
tree.treeBoxObject.invalidateColumn(col.mTargetCol.id);
|
|
sib = col.mTargetCol._previousVisibleColumn;
|
|
if (sib) {
|
|
sib.removeAttribute("insertafter");
|
|
tree.treeBoxObject.invalidateColumn(sib.id);
|
|
}
|
|
col.mTargetCol = null;
|
|
col.mTargetDir = null;
|
|
}
|
|
|
|
if (targetCol) {
|
|
// set insertbefore/after attributes
|
|
if (pos.value == "after") {
|
|
targetCol.setAttribute("insertafter", "true");
|
|
} else {
|
|
targetCol.setAttribute("insertbefore", "true");
|
|
sib = targetCol._previousVisibleColumn;
|
|
if (sib) {
|
|
sib.setAttribute("insertafter", "true");
|
|
tree.treeBoxObject.invalidateColumn(sib.id);
|
|
}
|
|
}
|
|
tree.treeBoxObject.invalidateColumn(targetCol.id);
|
|
col.mTargetCol = targetCol;
|
|
col.mTargetDir = pos.value;
|
|
}
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="onDragMouseUp">
|
|
<parameter name="aEvent"/>
|
|
<body><![CDATA[
|
|
var col = document.treecolDragging;
|
|
if (!col) return;
|
|
|
|
if (!col.mDragGesturing) {
|
|
if (col.mTargetCol) {
|
|
// remove insertbefore/after attributes
|
|
var before = col.mTargetCol.hasAttribute("insertbefore");
|
|
col.mTargetCol.removeAttribute(before ? "insertbefore" : "insertafter");
|
|
if (before) {
|
|
var sib = col.mTargetCol._previousVisibleColumn;
|
|
if (sib)
|
|
sib.removeAttribute("insertafter");
|
|
}
|
|
|
|
// move the column
|
|
if (col != col.mTargetCol)
|
|
col.parentNode.parentNode._reorderColumn(col, col.mTargetCol, before);
|
|
|
|
// repaint to remove lines
|
|
col.parentNode.parentNode.treeBoxObject.invalidate();
|
|
|
|
col.mTargetCol = null;
|
|
}
|
|
} else
|
|
col.mDragGesturing = false;
|
|
|
|
document.treecolDragging = null;
|
|
col.removeAttribute("dragging");
|
|
|
|
window.removeEventListener("mousemove", col.onDragMouseMove, true);
|
|
window.removeEventListener("mouseup", col.onDragMouseUp, true);
|
|
// we have to wait for the click event to fire before removing
|
|
// cancelling handler
|
|
var clickHandler = function(handler) {
|
|
window.removeEventListener("click", handler, true);
|
|
};
|
|
window.setTimeout(clickHandler, 0, col.onDragMouseClick);
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="onDragMouseClick">
|
|
<parameter name="aEvent"/>
|
|
<body><![CDATA[
|
|
// prevent click event from firing after column drag and drop
|
|
aEvent.preventBubble();
|
|
aEvent.preventDefault();
|
|
]]></body>
|
|
</method>
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="mousedown" button="0"><![CDATA[
|
|
if (this.parentNode.parentNode.enableColumnDrag) {
|
|
var xulns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|
var cols = this.parentNode.getElementsByTagNameNS(xulns, "treecol");
|
|
|
|
// only start column drag operation if there are at least 2 visible columns
|
|
var visible = 0;
|
|
for (var i = 0; i < cols.length; ++i)
|
|
if (cols[i].boxObject.width > 0) ++visible;
|
|
|
|
if (visible > 1) {
|
|
window.addEventListener("mousemove", this.onDragMouseMove, false);
|
|
window.addEventListener("mouseup", this.onDragMouseUp, false);
|
|
document.treecolDragging = this;
|
|
this.mDragGesturing = true;
|
|
this.mStartDragX = event.clientX;
|
|
this.mStartDragY = event.clientY;
|
|
}
|
|
}
|
|
]]></handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
<binding id="treecol" extends="chrome://global/content/bindings/tree.xml#treecol-base">
|
|
<content>
|
|
<xul:label class="treecol-text" xbl:inherits="crop,value=label" flex="1" crop="right"/>
|
|
<xul:image class="treecol-sortdirection" xbl:inherits="sortDirection"/>
|
|
</content>
|
|
<implementation implements="nsIAccessibleProvider">
|
|
<property name="accessible">
|
|
<getter>
|
|
<![CDATA[
|
|
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
|
|
return accService.createXULTreeColumnitemAccessible(this);
|
|
]]>
|
|
</getter>
|
|
</property>
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="click" button="0" phase="target" action="this.parentNode.parentNode.treeBoxObject.view.cycleHeader(this.id, this);"/>
|
|
</handlers>
|
|
</binding>
|
|
|
|
<binding id="treecol-image" extends="chrome://global/content/bindings/tree.xml#treecol-base">
|
|
<content>
|
|
<xul:image class="treecol-icon" xbl:inherits="src"/>
|
|
</content>
|
|
<handlers>
|
|
<handler event="click" button="0" action="this.parentNode.parentNode.treeBoxObject.view.cycleHeader(this.id, this)"/>
|
|
</handlers>
|
|
</binding>
|
|
|
|
<binding id="columnpicker" display="xul:button"
|
|
extends="chrome://global/content/bindings/tree.xml#tree-base">
|
|
<content>
|
|
<xul:image class="tree-columnpicker-icon"/>
|
|
<xul:menupopup anonid="popup"/>
|
|
</content>
|
|
|
|
<implementation>
|
|
<method name="buildPopup">
|
|
<parameter name="aPopup"/>
|
|
<body>
|
|
<![CDATA[
|
|
// we no longer cache the picker content.
|
|
// remove the old content
|
|
while (aPopup.hasChildNodes())
|
|
aPopup.removeChild(aPopup.lastChild);
|
|
|
|
for (var currCol = this.parentNode.firstChild; currCol; currCol = currCol.nextSibling) {
|
|
// Construct an entry for each column in the row, unless
|
|
// it is not being shown
|
|
if (currCol.localName == "treecol" && !currCol.hasAttribute("ignoreincolumnpicker")) {
|
|
var popupChild = document.createElement("menuitem");
|
|
popupChild.setAttribute("type", "checkbox");
|
|
var columnName = currCol.getAttribute("display") || currCol.getAttribute("label");
|
|
popupChild.setAttribute("label", columnName);
|
|
popupChild.setAttribute("colid", currCol.id);
|
|
if (currCol.getAttribute("hidden") != "true")
|
|
popupChild.setAttribute("checked", "true");
|
|
if (currCol.getAttribute("primary") == "true")
|
|
popupChild.setAttribute("disabled", "true");
|
|
aPopup.appendChild(popupChild);
|
|
}
|
|
}
|
|
]]>
|
|
</body>
|
|
</method>
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="command">
|
|
<![CDATA[
|
|
if (event.originalTarget == this) {
|
|
var popup = document.getAnonymousElementByAttribute(this, "anonid", "popup");
|
|
this.buildPopup(popup);
|
|
popup.showPopup(this, -1, -1, "popup", "bottomright", "topright");
|
|
} else {
|
|
var colid = event.originalTarget.getAttribute("colid");
|
|
var colNode = document.getElementById(colid);
|
|
if (colNode) {
|
|
if (colNode.getAttribute("hidden") == "true")
|
|
colNode.setAttribute("hidden", "false");
|
|
else
|
|
colNode.setAttribute("hidden", "true");
|
|
}
|
|
}
|
|
]]>
|
|
</handler>
|
|
</handlers>
|
|
</binding>
|
|
</bindings>
|
|
|