2008-07-16 08:41:38 -07:00
|
|
|
<?xml version="1.0"?>
|
2008-12-15 08:44:27 -08:00
|
|
|
|
|
|
|
<!DOCTYPE bindings [
|
|
|
|
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
|
|
|
|
%browserDTD;
|
|
|
|
]>
|
2008-07-16 08:41:38 -07:00
|
|
|
|
|
|
|
<bindings
|
|
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
|
|
xmlns:xbl="http://www.mozilla.org/xbl"
|
|
|
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
|
|
|
|
|
|
|
<binding id="autocomplete-aligned" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
|
|
|
|
<implementation>
|
|
|
|
<method name="openPopup">
|
|
|
|
<body><![CDATA[
|
2009-07-31 14:03:47 -07:00
|
|
|
this.popup.openAutocompletePopup(this, null);
|
2008-07-16 08:41:38 -07:00
|
|
|
]]></body>
|
|
|
|
</method>
|
|
|
|
<method name="closePopup">
|
|
|
|
<body><![CDATA[
|
2009-07-31 14:03:47 -07:00
|
|
|
// hack! we want to revert to the "all results" popup when the
|
|
|
|
// controller would otherwise close us because of an empty search
|
2009-09-18 21:17:52 -07:00
|
|
|
// string.
|
2009-07-31 14:03:47 -07:00
|
|
|
if (this.value == "")
|
|
|
|
this.showHistoryPopup();
|
2008-07-16 08:41:38 -07:00
|
|
|
]]></body>
|
|
|
|
</method>
|
|
|
|
</implementation>
|
2009-07-31 14:03:47 -07:00
|
|
|
<handlers>
|
|
|
|
<handler event="keypress" keycode="VK_RETURN" phase="capturing">
|
|
|
|
<![CDATA[
|
|
|
|
if (this.popup.allBookmarksItemSelected) {
|
|
|
|
this.popup.closePopup();
|
|
|
|
CommandUpdater.doCommand("cmd_bookmarks");
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</handler>
|
|
|
|
</handlers>
|
2008-07-16 08:41:38 -07:00
|
|
|
</binding>
|
2009-02-24 22:20:45 -08:00
|
|
|
|
2009-07-28 15:49:09 -07:00
|
|
|
<binding id="popup_autocomplete_result">
|
2009-09-21 14:09:47 -07:00
|
|
|
<content orient="vertical">
|
|
|
|
<xul:hbox class="autocomplete-item-label" align="center" xbl:inherits="tags, favorite" mousethrough="always">
|
|
|
|
<xul:image xbl:inherits="src"/>
|
|
|
|
<xul:label flex="1" crop="center" xbl:inherits="value"/>
|
|
|
|
</xul:hbox>
|
|
|
|
<xul:label class="autocomplete-item-url" xbl:inherits="value=url" crop="center" mousethrough="always"/>
|
2009-07-28 15:49:09 -07:00
|
|
|
</content>
|
|
|
|
</binding>
|
|
|
|
|
2008-12-09 10:38:31 -08:00
|
|
|
<binding id="popup_autocomplete">
|
2009-07-28 15:49:09 -07:00
|
|
|
<content>
|
2008-12-09 10:38:31 -08:00
|
|
|
<xul:vbox class="autocomplete-box" flex="1">
|
2009-09-02 11:11:00 -07:00
|
|
|
<!-- 12 child items, to match browser.urlbar.maxRichResults -->
|
2009-04-30 18:09:48 -07:00
|
|
|
<xul:scrollbox orient="vertical"
|
|
|
|
class="autocomplete-items"
|
|
|
|
anonid="autocomplete-items"
|
|
|
|
flex="1000">
|
2009-07-31 14:03:47 -07:00
|
|
|
<xul:autocompleteresult anonid="allbookmarks"
|
|
|
|
value="&allBookmarks.label;"
|
|
|
|
class="allbookmarks"/>
|
2009-07-28 15:49:09 -07:00
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
2009-09-02 11:11:00 -07:00
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
|
|
|
<xul:autocompleteresult/>
|
2009-04-30 18:09:48 -07:00
|
|
|
</xul:scrollbox>
|
2008-12-09 10:38:31 -08:00
|
|
|
<children/>
|
|
|
|
</xul:vbox>
|
|
|
|
</content>
|
|
|
|
|
2009-11-05 14:02:22 -08:00
|
|
|
<implementation implements="nsIAutoCompletePopup">
|
2009-04-30 18:09:48 -07:00
|
|
|
<!-- Used by the chrome input handler -->
|
|
|
|
<property name="boxObject"
|
|
|
|
readonly="true"
|
|
|
|
onget="return this._items.boxObject;"/>
|
|
|
|
|
2009-07-02 11:49:08 -07:00
|
|
|
<field name="_scrollBoxObject">
|
|
|
|
this.boxObject.QueryInterface(Components.interfaces.nsIScrollBoxObject);
|
|
|
|
</field>
|
|
|
|
|
2008-12-09 10:38:31 -08:00
|
|
|
<!-- nsIAutocompleteInput -->
|
|
|
|
<property name="overrideValue"
|
|
|
|
readonly="true"
|
|
|
|
onget="return null;"/>
|
|
|
|
|
|
|
|
<field name="_input"/>
|
|
|
|
<property name="input"
|
|
|
|
readonly="true"
|
|
|
|
onget="return this._input;"/>
|
|
|
|
|
|
|
|
<field name="_selectedIndex">-1</field>
|
|
|
|
<field name="_selectedItem"/>
|
|
|
|
<property name="selectedIndex"
|
2009-07-31 14:03:47 -07:00
|
|
|
onget="return this._allBookmarksItem._hidden ? this._selectedIndex : this._selectedIndex - 1;">
|
2008-12-09 10:38:31 -08:00
|
|
|
<setter><![CDATA[
|
|
|
|
// Ignore invalid indices
|
|
|
|
if (val < -1 ||
|
|
|
|
val > this._matchCount - 1)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
if (this._selectedItem)
|
|
|
|
this._styleItem(this._selectedItem, false);
|
|
|
|
|
|
|
|
// highlight the selected item
|
|
|
|
let item = this._items.childNodes.item(val);
|
|
|
|
if (item) {
|
|
|
|
this._selectedItem = item;
|
|
|
|
this._styleItem(this._selectedItem, true);
|
2009-08-18 22:55:03 -07:00
|
|
|
this._scrollBoxObject.ensureElementIsVisible(this._selectedItem);
|
2008-12-09 10:38:31 -08:00
|
|
|
}
|
2009-02-24 22:20:45 -08:00
|
|
|
|
2008-12-09 10:38:31 -08:00
|
|
|
return this._selectedIndex = val;
|
|
|
|
]]></setter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<field name="_popupOpen">false</field>
|
|
|
|
<property name="popupOpen"
|
|
|
|
readonly="true"
|
|
|
|
onget="return this._popupOpen;"/>
|
|
|
|
|
|
|
|
<method name="openAutocompletePopup">
|
|
|
|
<parameter name="aInput"/>
|
|
|
|
<parameter name="aElement"/>
|
|
|
|
<body><![CDATA[
|
|
|
|
if (this._popupOpen)
|
|
|
|
return;
|
|
|
|
|
2009-08-26 10:18:13 -07:00
|
|
|
BrowserUI.pushDialog(this);
|
|
|
|
|
2009-09-22 08:36:45 -07:00
|
|
|
this._selectedItem = null;
|
2008-12-09 10:38:31 -08:00
|
|
|
this._input = aInput;
|
2009-08-26 10:18:13 -07:00
|
|
|
this._input.select();
|
2008-12-09 10:38:31 -08:00
|
|
|
|
2009-07-28 15:49:09 -07:00
|
|
|
if (this.hidden)
|
|
|
|
this.hidden = false;
|
|
|
|
this.collapsed = false;
|
2008-12-09 10:38:31 -08:00
|
|
|
this._popupOpen = true;
|
|
|
|
|
|
|
|
this.invalidate();
|
|
|
|
]]></body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="closePopup">
|
|
|
|
<body><![CDATA[
|
|
|
|
if (!this._popupOpen)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.selectedIndex = -1;
|
|
|
|
this.input.controller.stopSearch();
|
|
|
|
|
2009-07-28 15:49:09 -07:00
|
|
|
this.collapsed = true;
|
2008-12-09 10:38:31 -08:00
|
|
|
this._popupOpen = false;
|
2009-07-08 07:55:07 -07:00
|
|
|
|
2009-09-01 11:05:43 -07:00
|
|
|
// Scroll to the top left for the next open (only if necessary).
|
|
|
|
// Doing this now rather than in open() turns out to be faster,
|
|
|
|
// possibly because it avoids scrolling too soon after we uncollapse
|
|
|
|
// ourselves
|
|
|
|
if (this._items.scrollTop || this._items.scrollLeft)
|
|
|
|
this._scrollBoxObject.scrollTo(0, 0);
|
|
|
|
|
2009-09-18 21:17:52 -07:00
|
|
|
BrowserUI.showToolbar(false);
|
2009-07-08 07:55:07 -07:00
|
|
|
BrowserUI.popDialog();
|
|
|
|
]]></body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<!-- Helper used by active dialog system -->
|
|
|
|
<method name="close">
|
|
|
|
<body><![CDATA[
|
2009-08-24 08:00:28 -07:00
|
|
|
this.input.reset();
|
2009-09-18 21:17:52 -07:00
|
|
|
this.input.blur();
|
2009-07-08 07:55:07 -07:00
|
|
|
this.closePopup();
|
2008-12-09 10:38:31 -08:00
|
|
|
]]></body>
|
|
|
|
</method>
|
|
|
|
|
2009-04-30 18:09:48 -07:00
|
|
|
<field name="_XULNS">("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")</field>
|
|
|
|
|
2008-12-09 10:38:31 -08:00
|
|
|
<method name="invalidate">
|
|
|
|
<body><![CDATA[
|
|
|
|
// Don't bother doing work if we're not even open
|
|
|
|
if (!this.popupOpen)
|
|
|
|
return;
|
|
|
|
|
2009-07-31 14:03:47 -07:00
|
|
|
let controller = this.input.controller;
|
|
|
|
let searchString = controller.searchString;
|
|
|
|
let items = this._items;
|
|
|
|
|
|
|
|
// Remove the allBookmarksItem if present, before populating the list.
|
|
|
|
if (!this._allBookmarksItem._hidden) {
|
|
|
|
items.removeChild(this._allBookmarksItem);
|
|
|
|
this._allBookmarksItem._hidden = true;
|
|
|
|
}
|
|
|
|
|
2009-04-30 18:09:48 -07:00
|
|
|
// Need to iterate over all our existing entries at a minimum, to make
|
|
|
|
// sure they're either updated or cleared out. We might also have to
|
|
|
|
// add extra items.
|
2009-05-26 08:46:39 -07:00
|
|
|
let matchCount = this._matchCount;
|
2009-07-28 15:49:09 -07:00
|
|
|
let children = items.childNodes;
|
2009-05-26 08:46:39 -07:00
|
|
|
let iterCount = Math.max(children.length, matchCount);
|
2009-04-30 18:09:48 -07:00
|
|
|
for (let i = 0; i < iterCount; ++i) {
|
2009-07-28 15:49:09 -07:00
|
|
|
let item = children.item(i);
|
2009-04-30 18:09:48 -07:00
|
|
|
|
2009-07-28 15:49:09 -07:00
|
|
|
// Create an item if needed
|
|
|
|
if (!item) {
|
|
|
|
item = document.createElementNS(this._XULNS, "xul:autocompleteresult");
|
|
|
|
items.appendChild(item);
|
2009-05-26 08:46:39 -07:00
|
|
|
}
|
2009-09-02 11:11:00 -07:00
|
|
|
|
2009-07-28 15:49:09 -07:00
|
|
|
item._index = i;
|
2009-05-26 08:46:39 -07:00
|
|
|
|
2008-12-09 10:38:31 -08:00
|
|
|
// Check whether there's an entry to fill
|
|
|
|
if (i > matchCount - 1) {
|
2009-11-10 11:47:38 -08:00
|
|
|
// Just clear out the old item's value. CSS takes care of hiding
|
|
|
|
// everything else based on value="" (star, tags, etc.)
|
2009-07-28 15:49:09 -07:00
|
|
|
item.setAttribute("value", "");
|
|
|
|
item._empty = true;
|
2008-12-09 10:38:31 -08:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2009-07-28 15:49:09 -07:00
|
|
|
item._empty = false;
|
2008-12-09 10:38:31 -08:00
|
|
|
|
2009-07-28 15:49:09 -07:00
|
|
|
// Assign the values
|
2008-12-09 10:38:31 -08:00
|
|
|
let type = controller.getStyleAt(i);
|
2009-07-28 15:49:09 -07:00
|
|
|
let title = controller.getCommentAt(i);
|
|
|
|
let tags = '';
|
|
|
|
|
|
|
|
if (type == "tag")
|
|
|
|
[, title, tags] = title.match(/^(.+) \u2013 (.+)$/);
|
|
|
|
item.setAttribute("tags", tags);
|
2008-12-09 10:38:31 -08:00
|
|
|
|
2009-07-28 15:49:09 -07:00
|
|
|
let url = controller.getValueAt(i);
|
2009-09-21 14:09:47 -07:00
|
|
|
item.setAttribute("value", title || url);
|
|
|
|
item.setAttribute("url", url);
|
2009-07-28 15:49:09 -07:00
|
|
|
|
|
|
|
let isBookmark = ((type == "bookmark") || (type == "tag"));
|
|
|
|
item.setAttribute("favorite", isBookmark);
|
|
|
|
item.setAttribute("src", controller.getImageAt(i));
|
|
|
|
}
|
|
|
|
|
2009-07-31 14:03:47 -07:00
|
|
|
// Show the "no results" or "all bookmarks" entries as needed
|
2009-07-28 15:49:09 -07:00
|
|
|
this._updateNoResultsItem(matchCount);
|
2009-07-31 14:03:47 -07:00
|
|
|
if (searchString == "") {
|
|
|
|
items.insertBefore(this._allBookmarksItem, items.firstChild);
|
|
|
|
this._allBookmarksItem._hidden = false;
|
|
|
|
}
|
2009-07-28 15:49:09 -07:00
|
|
|
]]></body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="_updateNoResultsItem">
|
|
|
|
<parameter name="isResults" />
|
|
|
|
<body><![CDATA[
|
|
|
|
let noResultsItem = this._items.childNodes.item(1);
|
|
|
|
if (isResults) {
|
|
|
|
noResultsItem.className = "";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
noResultsItem.className = "noresults";
|
|
|
|
noResultsItem.setAttribute("value", "]]>&noResults.label;<![CDATA[");
|
2009-11-10 11:47:38 -08:00
|
|
|
noResultsItem.removeAttribute("favorite");
|
|
|
|
noResultsItem.removeAttribute("url");
|
|
|
|
noResultsItem.removeAttribute("src");
|
|
|
|
noResultsItem.removeAttribute("tags");
|
2009-07-28 15:49:09 -07:00
|
|
|
}
|
|
|
|
]]></body>
|
|
|
|
</method>
|
|
|
|
|
2009-07-31 14:03:47 -07:00
|
|
|
<field name="_allBookmarksItem">document.getAnonymousElementByAttribute(this, "anonid", "allbookmarks");</field>
|
|
|
|
|
|
|
|
<property name="allBookmarksItemSelected" readonly="true"
|
|
|
|
onget="return this._selectedItem == this._allBookmarksItem;"/>
|
|
|
|
|
2008-12-09 10:38:31 -08:00
|
|
|
<method name="selectBy">
|
|
|
|
<parameter name="aReverse"/>
|
|
|
|
<parameter name="aPage"/>
|
|
|
|
<body><![CDATA[
|
|
|
|
let newIndex;
|
|
|
|
let lastIndex = this._matchCount - 1;
|
|
|
|
|
|
|
|
if (this._selectedIndex == -1)
|
|
|
|
newIndex = aReverse ? lastIndex : 0;
|
|
|
|
else
|
|
|
|
newIndex = this._selectedIndex + (aReverse ? -1 : 1);
|
|
|
|
|
|
|
|
// Deal with rollover
|
|
|
|
if (newIndex > lastIndex)
|
|
|
|
newIndex = 0;
|
|
|
|
else if (newIndex < 0)
|
|
|
|
newIndex = lastIndex;
|
|
|
|
|
|
|
|
this.selectedIndex = newIndex;
|
|
|
|
]]></body>
|
|
|
|
</method>
|
2009-02-24 22:20:45 -08:00
|
|
|
|
2008-12-09 10:38:31 -08:00
|
|
|
<!-- Helpers -->
|
|
|
|
<field name="_items">
|
|
|
|
document.getAnonymousElementByAttribute(this,
|
|
|
|
"anonid", "autocomplete-items");
|
|
|
|
</field>
|
|
|
|
|
|
|
|
<property name="_matchCount"
|
|
|
|
readonly="true">
|
|
|
|
<getter><![CDATA[
|
2009-09-02 11:11:00 -07:00
|
|
|
let matchCount = this.input.controller.matchCount;
|
|
|
|
return matchCount + (this._allBookmarksItem._hidden ? 0 : 1);
|
2008-12-09 10:38:31 -08:00
|
|
|
]]></getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<method name="_styleItem">
|
|
|
|
<parameter name="aItem"/>
|
|
|
|
<parameter name="aAddStyle"/>
|
|
|
|
<body><![CDATA[
|
|
|
|
if (aAddStyle)
|
2009-07-31 14:03:47 -07:00
|
|
|
aItem.className += " autocompleteresult-selected";
|
2008-12-09 10:38:31 -08:00
|
|
|
else
|
2009-07-31 14:03:47 -07:00
|
|
|
aItem.className = aItem.className.replace(/\s*autocompleteresult-selected/, "");
|
2008-12-09 10:38:31 -08:00
|
|
|
]]></body>
|
|
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
|
|
|
|
<handlers>
|
2009-07-31 14:03:47 -07:00
|
|
|
<handler event="click" button="0">
|
2008-12-09 10:38:31 -08:00
|
|
|
<![CDATA[
|
2009-09-15 10:06:21 -07:00
|
|
|
let target = event.originalTarget;
|
|
|
|
if (target == this._allBookmarksItem) {
|
2009-10-27 22:53:47 -07:00
|
|
|
this._selectedIndex = 0;
|
2009-09-11 07:45:29 -07:00
|
|
|
this.close();
|
2009-07-31 14:03:47 -07:00
|
|
|
CommandUpdater.doCommand("cmd_bookmarks");
|
2009-09-21 14:09:47 -07:00
|
|
|
}
|
|
|
|
else if (target.localName == "autocompleteresult" && !target._empty) {
|
2009-07-31 14:03:47 -07:00
|
|
|
let offset = this._allBookmarksItem._hidden ? 0 : 1;
|
2009-10-27 22:53:47 -07:00
|
|
|
this._selectedIndex = target._index + offset;
|
2008-12-09 10:38:31 -08:00
|
|
|
this.input.controller.handleEnter(true);
|
2009-09-11 07:45:29 -07:00
|
|
|
}
|
2008-12-09 10:38:31 -08:00
|
|
|
]]>
|
|
|
|
</handler>
|
|
|
|
</handlers>
|
|
|
|
</binding>
|
2008-07-16 08:41:38 -07:00
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
<binding id="place-base">
|
|
|
|
<content/>
|
2008-12-15 08:44:27 -08:00
|
|
|
<implementation>
|
2009-04-08 22:40:05 -07:00
|
|
|
<field name="_uri">null</field>
|
2009-02-24 22:20:45 -08:00
|
|
|
<field name="_control">null</field>
|
2009-02-24 22:20:45 -08:00
|
|
|
<field name="_isEditing">false</field>
|
|
|
|
|
2009-12-14 12:26:51 -08:00
|
|
|
<field name="_ioService">
|
2009-04-08 22:40:05 -07:00
|
|
|
Components.classes["@mozilla.org/network/io-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIIOService);
|
|
|
|
</field>
|
|
|
|
|
2008-12-15 08:44:27 -08:00
|
|
|
<field name="_nameField">
|
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "name");
|
|
|
|
</field>
|
|
|
|
<field name="_uriField">
|
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "uri");
|
|
|
|
</field>
|
|
|
|
<field name="_tagsField">
|
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "tags");
|
|
|
|
</field>
|
2009-11-23 08:44:34 -08:00
|
|
|
<property name="itemId" onget="return this.getAttribute('itemid');"/>
|
2009-02-24 22:20:45 -08:00
|
|
|
<property name="type" onget="return this.getAttribute('type');"/>
|
2009-02-24 22:20:45 -08:00
|
|
|
|
2009-11-23 08:44:34 -08:00
|
|
|
<property name="uri">
|
|
|
|
<getter><![CDATA[
|
|
|
|
if (!this._uri && this.getAttribute("uri"))
|
|
|
|
this._uri = this._ioService.newURI(this.getAttribute("uri"), null, null);
|
|
|
|
|
|
|
|
return this._uri;
|
|
|
|
]]></getter>
|
|
|
|
</property>
|
|
|
|
|
2008-12-15 08:44:27 -08:00
|
|
|
<property name="name" onget="return this._nameField.value"
|
|
|
|
onset="this._nameField.value = val; return val;"/>
|
2009-02-24 22:20:45 -08:00
|
|
|
<property name="spec" onget="return this._uriField.value"
|
|
|
|
onset="this._uriField.value = val; return val;"/>
|
2008-12-15 08:44:27 -08:00
|
|
|
<property name="tags" onget="return this._tagsField.value"
|
|
|
|
onset="this._tagsField.value = val; return val;"/>
|
|
|
|
<property name="tagsAsArray" readonly="true">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
// we don't require the leading space (after each comma)
|
|
|
|
var tags = this.tags.split(",");
|
|
|
|
for (var i = 0; i < tags.length; i++) {
|
|
|
|
// remove trailing and leading spaces
|
|
|
|
tags[i] = tags[i].trim();
|
|
|
|
|
|
|
|
// remove empty entries from the array.
|
|
|
|
if (tags[i] == "") {
|
|
|
|
tags.splice(i, 1);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tags;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
2009-02-24 22:20:45 -08:00
|
|
|
<property name="isEditing" readonly="true" onget="return this._isEditing;"/>
|
|
|
|
<property name="control" readonly="true">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
2009-02-24 22:20:45 -08:00
|
|
|
if (this._control)
|
|
|
|
return this._control;
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
let parent = this.parentNode;
|
|
|
|
while (parent) {
|
2009-02-24 22:20:45 -08:00
|
|
|
if (parent.localName == "placelist") {
|
|
|
|
this._control = parent;
|
|
|
|
return this._control;
|
|
|
|
}
|
2009-02-24 22:20:45 -08:00
|
|
|
parent = parent.parentNode;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
2008-12-15 08:44:27 -08:00
|
|
|
<method name="startEditing">
|
2009-03-03 06:31:51 -08:00
|
|
|
<parameter name="autoSelect"/>
|
2008-12-15 08:44:27 -08:00
|
|
|
<body>
|
|
|
|
<![CDATA[
|
2009-11-23 08:44:34 -08:00
|
|
|
if (!this.itemId)
|
2008-12-15 08:44:27 -08:00
|
|
|
return;
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
this._isEditing = true;
|
2009-09-09 18:47:37 -07:00
|
|
|
if (this.control) {
|
|
|
|
this.setAttribute("selected", "true");
|
|
|
|
this.control.scrollBoxObject.ensureElementIsVisible(this);
|
2009-02-24 22:20:45 -08:00
|
|
|
this.control.activeItem = this;
|
2009-09-09 18:47:37 -07:00
|
|
|
}
|
2008-12-15 08:44:27 -08:00
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
this.updateFields();
|
|
|
|
|
2008-12-15 08:44:27 -08:00
|
|
|
this._nameField.focus();
|
2009-03-03 06:31:51 -08:00
|
|
|
if (autoSelect)
|
|
|
|
this._nameField.select();
|
2008-12-15 08:44:27 -08:00
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
<method name="stopEditing">
|
|
|
|
<parameter name="shouldSave"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (shouldSave)
|
|
|
|
this.save();
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
this._isEditing = false;
|
2009-09-09 18:47:37 -07:00
|
|
|
if (this.control) {
|
|
|
|
this.control.activeItem.removeAttribute("selected");
|
2009-02-24 22:20:45 -08:00
|
|
|
this.control.activeItem = null;
|
2009-09-09 18:47:37 -07:00
|
|
|
}
|
2009-02-24 22:20:45 -08:00
|
|
|
|
|
|
|
this.updateFields();
|
|
|
|
|
2009-10-21 19:01:54 -07:00
|
|
|
let focusedElement = document.commandDispatcher.focusedElement;
|
|
|
|
if (focusedElement)
|
|
|
|
focusedElement.blur();
|
|
|
|
|
2008-12-15 08:44:27 -08:00
|
|
|
let event = document.createEvent("Events");
|
|
|
|
event.initEvent("close", true, false);
|
|
|
|
this.dispatchEvent(event);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
<method name="save">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
// Update the tags
|
2009-11-23 08:44:34 -08:00
|
|
|
if (this.uri && this.type != "folder") {
|
|
|
|
let currentTags = PlacesUtils.tagging.getTagsForURI(this.uri, {});
|
2009-04-21 13:55:05 -07:00
|
|
|
let tags = this.tagsAsArray;
|
2009-02-24 22:20:45 -08:00
|
|
|
if (tags.length > 0 || currentTags.length > 0) {
|
2009-04-21 13:55:05 -07:00
|
|
|
let tagsToRemove = [];
|
|
|
|
let tagsToAdd = [];
|
|
|
|
for (let i = 0; i < currentTags.length; i++) {
|
2009-02-24 22:20:45 -08:00
|
|
|
if (tags.indexOf(currentTags[i]) == -1)
|
|
|
|
tagsToRemove.push(currentTags[i]);
|
|
|
|
}
|
2009-04-21 13:55:05 -07:00
|
|
|
for (let i = 0; i < tags.length; i++) {
|
2009-02-24 22:20:45 -08:00
|
|
|
if (currentTags.indexOf(tags[i]) == -1)
|
|
|
|
tagsToAdd.push(tags[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tagsToAdd.length > 0)
|
2009-11-23 08:44:34 -08:00
|
|
|
PlacesUtils.tagging.tagURI(this.uri, tagsToAdd);
|
2009-02-24 22:20:45 -08:00
|
|
|
if (tagsToRemove.length > 0)
|
2009-11-23 08:44:34 -08:00
|
|
|
PlacesUtils.tagging.untagURI(this.uri, tagsToRemove);
|
2008-12-15 08:44:27 -08:00
|
|
|
}
|
2009-09-09 18:47:37 -07:00
|
|
|
this.setAttribute('tags', this.tags);
|
2008-12-15 08:44:27 -08:00
|
|
|
|
2009-04-21 13:55:05 -07:00
|
|
|
// If the URI was updated change it in the bookmark, but don't
|
|
|
|
// allow a blank URI. Revert to previous URI if blank.
|
|
|
|
let spec = this.spec;
|
2009-11-23 08:44:34 -08:00
|
|
|
if (spec && this.uri.spec != spec) {
|
2009-04-21 13:55:05 -07:00
|
|
|
try {
|
2010-02-16 15:38:16 -08:00
|
|
|
let oldURI = this._uri;
|
2009-04-21 13:55:05 -07:00
|
|
|
this._uri = this._ioService.newURI(spec, null, null);
|
2009-11-23 08:44:34 -08:00
|
|
|
PlacesUtils.bookmarks.changeBookmarkURI(this.itemId, this.uri);
|
2009-09-09 18:47:37 -07:00
|
|
|
this.setAttribute('uri', this.spec);
|
2010-02-16 15:38:16 -08:00
|
|
|
|
|
|
|
// move tags from old URI to new URI
|
|
|
|
let tags = this.tagsAsArray;
|
|
|
|
if (tags.length != 0) {
|
|
|
|
// only untag the old URI if this is the only bookmark
|
|
|
|
if (PlacesUtils.getBookmarksForURI(oldURI, {}).length == 0)
|
|
|
|
PlacesUtils.tagging.untagURI(oldURI, tags);
|
|
|
|
|
|
|
|
PlacesUtils.tagging.tagURI(this._uri, tags);
|
|
|
|
}
|
2009-04-21 13:55:05 -07:00
|
|
|
}
|
|
|
|
catch (e) { }
|
2009-02-24 22:20:45 -08:00
|
|
|
}
|
2009-11-23 08:44:34 -08:00
|
|
|
if (spec != this.uri.spec)
|
2009-11-24 06:37:26 -08:00
|
|
|
this.spec = this.uri.spec;
|
2008-12-15 08:44:27 -08:00
|
|
|
}
|
2009-04-21 13:55:05 -07:00
|
|
|
|
|
|
|
// Update the name and use the URI if name is blank
|
2009-11-24 06:37:26 -08:00
|
|
|
this.name = this.name || this.spec;
|
2009-09-09 18:47:37 -07:00
|
|
|
this.setAttribute('title', this.name);
|
2009-11-23 08:44:34 -08:00
|
|
|
PlacesUtils.bookmarks.setItemTitle(this.itemId, this.name);
|
2008-12-15 08:44:27 -08:00
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
<method name="remove">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
2009-11-23 08:44:34 -08:00
|
|
|
PlacesUtils.bookmarks.removeItem(this.itemId);
|
2008-12-15 08:44:27 -08:00
|
|
|
|
|
|
|
// If this was the last bookmark (excluding tag-items and livemark
|
|
|
|
// children, see getMostRecentBookmarkForURI) for the bookmark's url,
|
|
|
|
// remove the url from tag containers as well.
|
2009-11-23 08:44:34 -08:00
|
|
|
if (this.uri && this.type != "folder") {
|
|
|
|
if (PlacesUtils.getMostRecentBookmarkForURI(this.uri) == -1) {
|
|
|
|
var tags = PlacesUtils.tagging.getTagsForURI(this.uri, {});
|
|
|
|
PlacesUtils.tagging.untagURI(this.uri, tags);
|
2009-02-24 22:20:45 -08:00
|
|
|
}
|
2008-12-15 08:44:27 -08:00
|
|
|
}
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
this.stopEditing(false);
|
|
|
|
|
2008-12-15 08:44:27 -08:00
|
|
|
let event = document.createEvent("Events");
|
2009-02-24 22:20:45 -08:00
|
|
|
event.initEvent("BookmarkRemove", true, false);
|
2008-12-15 08:44:27 -08:00
|
|
|
this.dispatchEvent(event);
|
2009-10-20 20:32:36 -07:00
|
|
|
|
|
|
|
if (this.control)
|
|
|
|
this.control.removeItem(this);
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
<method name="updateFields">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
// implemented by sub classes
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
</binding>
|
2008-12-15 08:44:27 -08:00
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
<binding id="place-item" extends="chrome://browser/content/bindings.xml#place-base">
|
2009-10-09 11:06:51 -07:00
|
|
|
<content orient="vertical">
|
|
|
|
<xul:hbox anonid="bookmark-item" class="bookmark-item-label" align="center" flex="1" xbl:inherits="tags" mousethrough="always">
|
|
|
|
<xul:image xbl:inherits="src"/>
|
|
|
|
<xul:label flex="1" crop="center" xbl:inherits="value=title"/>
|
|
|
|
</xul:hbox>
|
|
|
|
<xul:label anonid="bookmark-url" class="bookmark-item-url" xbl:inherits="value=uri" crop="center" mousethrough="always"/>
|
2009-09-09 18:47:37 -07:00
|
|
|
|
2009-10-09 11:06:51 -07:00
|
|
|
<xul:hbox anonid="bookmark-manage" class="bookmark-manage" hidden="true" flex="1">
|
|
|
|
<xul:image xbl:inherits="src"/>
|
2009-09-09 18:47:37 -07:00
|
|
|
<xul:vbox flex="1">
|
2009-10-09 11:06:51 -07:00
|
|
|
<xul:vbox flex="1">
|
2009-09-09 18:47:37 -07:00
|
|
|
<xul:textbox anonid="name" xbl:inherits="value=title"/>
|
2009-02-24 22:20:45 -08:00
|
|
|
<xul:textbox anonid="uri" xbl:inherits="value=uri"/>
|
|
|
|
<xul:textbox anonid="tags" xbl:inherits="value=tags" emptytext="&editBookmarkTags.label;"/>
|
2009-09-09 18:47:37 -07:00
|
|
|
</xul:vbox>
|
|
|
|
|
2009-10-09 11:06:51 -07:00
|
|
|
<xul:hbox class="bookmark-controls" align="center">
|
2009-10-15 19:55:17 -07:00
|
|
|
<xul:button anonid="remove-button" class="bookmark-remove" label="&editBookmarkRemove.label;"
|
2009-10-09 11:06:51 -07:00
|
|
|
oncommand="document.getBindingParent(this).remove()"/>
|
2009-09-09 18:47:37 -07:00
|
|
|
<xul:spacer flex="1"/>
|
2009-10-15 19:55:17 -07:00
|
|
|
<xul:button anonid="done-button" class="bookmark-done" label="&editBookmarkDone.label;"
|
2009-09-09 18:47:37 -07:00
|
|
|
oncommand="document.getBindingParent(this).stopEditing(true)"/>
|
|
|
|
</xul:hbox>
|
|
|
|
</xul:vbox>
|
|
|
|
</xul:hbox>
|
2009-02-24 22:20:45 -08:00
|
|
|
</content>
|
2009-09-09 18:47:37 -07:00
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
<implementation>
|
|
|
|
<method name="updateFields">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
2009-10-09 11:06:51 -07:00
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "bookmark-item").hidden = this._isEditing;
|
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "bookmark-url").hidden = this._isEditing;
|
2009-02-24 22:20:45 -08:00
|
|
|
|
2009-10-09 11:06:51 -07:00
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "bookmark-manage").hidden = !this._isEditing;
|
2009-02-24 22:20:45 -08:00
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
</binding>
|
|
|
|
|
2009-09-09 18:47:37 -07:00
|
|
|
<binding id="place-folder" extends="chrome://browser/content/bindings.xml#place-item">
|
2009-02-24 22:20:45 -08:00
|
|
|
<implementation>
|
|
|
|
<method name="updateFields">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
2009-10-09 11:06:51 -07:00
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "bookmark-item").hidden = this._isEditing;
|
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "bookmark-url").hidden = this._isEditing;
|
|
|
|
|
2009-09-09 18:47:37 -07:00
|
|
|
this._uriField.hidden = true;
|
|
|
|
this._tagsField.hidden = true;
|
2009-10-09 11:06:51 -07:00
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "bookmark-manage").hidden = !this._isEditing;
|
2008-12-15 08:44:27 -08:00
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
</binding>
|
2009-02-24 22:20:45 -08:00
|
|
|
|
|
|
|
<binding id="place-label" extends="chrome://browser/content/bindings.xml#place-base">
|
|
|
|
<content align="center">
|
|
|
|
<xul:spacer xbl:inherits="width=indent"/>
|
|
|
|
<xul:image anonid="favicon" class="bookmark-folder-image"/>
|
2009-04-08 22:40:05 -07:00
|
|
|
<xul:label anonid="name" crop="end" flex="1" xbl:inherits="value=title"/>
|
2009-02-24 22:20:45 -08:00
|
|
|
</content>
|
|
|
|
</binding>
|
|
|
|
|
|
|
|
<binding id="place-list">
|
|
|
|
<content orient="vertical" flex="1">
|
2009-10-20 20:32:36 -07:00
|
|
|
<xul:vbox anonid="parent-items" class="place-list-parents" />
|
2009-02-24 22:20:45 -08:00
|
|
|
<xul:richlistbox anonid="child-items" class="place-list-children" flex="1"/>
|
|
|
|
</content>
|
|
|
|
<implementation>
|
|
|
|
<constructor>
|
|
|
|
<![CDATA[
|
|
|
|
this._type = this.getAttribute("type");
|
|
|
|
this._mode = this.getAttribute("mode");
|
2009-12-14 12:26:51 -08:00
|
|
|
|
|
|
|
this._folderParents = {};
|
|
|
|
this._folderParents[this._fakeDesktopFolderId] = this.mobileRoot;
|
|
|
|
this._folderParents[PlacesUtils.bookmarks.unfiledBookmarksFolder] = this._fakeDesktopFolderId;
|
|
|
|
this._folderParents[PlacesUtils.bookmarksMenuFolderId] = this._fakeDesktopFolderId;
|
|
|
|
this._folderParents[PlacesUtils.toolbarFolderId] = this._fakeDesktopFolderId;
|
2009-02-24 22:20:45 -08:00
|
|
|
]]>
|
|
|
|
</constructor>
|
2009-12-14 12:26:51 -08:00
|
|
|
<field name="_bundle">
|
2009-04-08 22:40:05 -07:00
|
|
|
Components.classes["@mozilla.org/intl/stringbundle;1"]
|
|
|
|
.getService(Components.interfaces.nsIStringBundleService)
|
|
|
|
.createBundle("chrome://browser/locale/browser.properties");
|
|
|
|
</field>
|
|
|
|
|
2009-12-14 12:26:51 -08:00
|
|
|
<field name="_fakeDesktopFolderId">-1000</field>
|
|
|
|
<field name="_desktopFolder"><![CDATA[
|
|
|
|
({
|
|
|
|
itemId: this._fakeDesktopFolderId, tags: "", uri: "",
|
|
|
|
title: Elements.browserBundle.getString("bookmarkList.desktop"),
|
|
|
|
type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER
|
|
|
|
})
|
|
|
|
]]></field>
|
|
|
|
<field name="_desktopChildren"><![CDATA[
|
|
|
|
[
|
|
|
|
{
|
|
|
|
itemId: PlacesUtils.bookmarks.unfiledBookmarksFolder, tags: "", uri: "",
|
|
|
|
title: PlacesUtils.bookmarks.getItemTitle(PlacesUtils.bookmarks.unfiledBookmarksFolder),
|
|
|
|
type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER
|
|
|
|
},
|
|
|
|
{
|
|
|
|
itemId: PlacesUtils.bookmarksMenuFolderId, tags: "", uri: "",
|
|
|
|
title: PlacesUtils.bookmarks.getItemTitle(PlacesUtils.bookmarksMenuFolderId),
|
|
|
|
type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER
|
|
|
|
},
|
|
|
|
{
|
|
|
|
itemId: PlacesUtils.toolbarFolderId, tags: "", uri: "",
|
|
|
|
title: PlacesUtils.bookmarks.getItemTitle(PlacesUtils.toolbarFolderId),
|
|
|
|
type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER
|
|
|
|
}
|
|
|
|
];
|
|
|
|
]]></field>
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
<field name="_type"/>
|
|
|
|
<field name="_mode"/>
|
|
|
|
<field name="_activeItem">null</field>
|
|
|
|
<field name="_ignoreEditing">false</field>
|
|
|
|
<field name="_manageUI">false</field>
|
|
|
|
<field name="_parents">
|
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "parent-items");
|
|
|
|
</field>
|
|
|
|
<field name="_children">
|
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "child-items");
|
|
|
|
</field>
|
|
|
|
|
2009-12-09 16:14:40 -08:00
|
|
|
<field name="scrollBoxObject">this._children.scrollBoxObject</field>
|
|
|
|
<!-- This won't be updated when the window size changes, but that's OK,
|
|
|
|
since we don't need an exact value - we just use it to get an
|
|
|
|
approximate scroll position for deciding whether to append additional
|
|
|
|
items (see batchSize/_insertItems()).
|
|
|
|
-->
|
|
|
|
<field name="_childrenHeight">this.scrollBoxObject.height;</field>
|
2009-02-27 11:44:35 -08:00
|
|
|
|
2009-10-20 20:32:36 -07:00
|
|
|
<property name="items" readonly="true" onget="return this._children.childNodes"/>
|
|
|
|
|
2009-11-19 11:40:54 -08:00
|
|
|
<field name="mobileRoot"><![CDATA[
|
|
|
|
PlacesUtils.annotations.getItemsWithAnnotation("mobile/bookmarksRoot", {})[0];
|
|
|
|
]]></field>
|
|
|
|
|
2009-10-20 20:32:36 -07:00
|
|
|
<property name="isRootFolder" readonly="true">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
let currentFolderId = this._parents.lastChild.getAttribute("itemid");
|
2009-11-19 11:40:54 -08:00
|
|
|
return currentFolderId == this.mobileRoot;
|
2009-10-20 20:32:36 -07:00
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
<property name="activeItem">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
return this._activeItem;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
|
|
|
if (!this._ignoreEditing) {
|
|
|
|
if (this._activeItem && this._activeItem.isEditing) {
|
|
|
|
this._ignoreEditing = true;
|
|
|
|
this._activeItem.stopEditing(false);
|
|
|
|
this._ignoreEditing = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._activeItem = val;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<property name="manageUI">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
return this._manageUI;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
|
|
|
if (this._manageUI != val) {
|
|
|
|
this._manageUI = val;
|
|
|
|
if (this._manageUI) {
|
|
|
|
this.setAttribute("ui", "manage");
|
2009-12-10 16:08:10 -08:00
|
|
|
if (this.getAttribute("autoedit") == "true" && this._children.hasChildNodes()) {
|
|
|
|
let first = this._getFirstVisibleChild();
|
|
|
|
if (first)
|
|
|
|
first.startEditing();
|
|
|
|
}
|
2009-02-24 22:20:45 -08:00
|
|
|
}
|
|
|
|
else {
|
2009-03-02 16:50:44 -08:00
|
|
|
if (this._activeItem && this._activeItem.isEditing)
|
2009-02-24 22:20:45 -08:00
|
|
|
this._activeItem.stopEditing();
|
|
|
|
this.removeAttribute("ui");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
|
2009-12-14 12:26:51 -08:00
|
|
|
<method name="isDesktopFolderEmpty">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
let options = PlacesUtils.history.getNewQueryOptions();
|
|
|
|
options.queryType = options.QUERY_TYPE_BOOKMARKS;
|
|
|
|
let query = PlacesUtils.history.getNewQuery();
|
|
|
|
let folders = [ PlacesUtils.bookmarks.unfiledBookmarksFolder,
|
|
|
|
PlacesUtils.bookmarksMenuFolderId,
|
|
|
|
PlacesUtils.toolbarFolderId
|
|
|
|
];
|
|
|
|
query.setFolders(folders, 3);
|
|
|
|
let result = PlacesUtils.history.executeQuery(query, options);
|
|
|
|
let rootNode = result.root;
|
|
|
|
rootNode.containerOpen = true;
|
|
|
|
let isEmpty = !rootNode.childCount;
|
|
|
|
rootNode.containerOpen = false;
|
|
|
|
|
|
|
|
return isEmpty;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
2009-12-10 16:08:10 -08:00
|
|
|
<method name="_getFirstVisibleChild">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
let children = this._children.childNodes;
|
|
|
|
for (let i = 0; i < children.length; i++) {
|
|
|
|
let rect = children[i].getBoundingClientRect();
|
|
|
|
let position = rect.top - rect.height;
|
|
|
|
if (position > 0)
|
|
|
|
return children[i];
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
<method name="_getChildren">
|
|
|
|
<parameter name="aFolder"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
let items = [];
|
|
|
|
|
|
|
|
let options = PlacesUtils.history.getNewQueryOptions();
|
|
|
|
options.queryType = (this._type == "bookmarks" ? options.QUERY_TYPE_BOOKMARKS : options.QUERY_TYPE_HISTORY);
|
2009-12-17 12:59:45 -08:00
|
|
|
|
|
|
|
// Exclude "query" items (e.g. "smart folders")
|
|
|
|
options.excludeQueries = true;
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
let query = PlacesUtils.history.getNewQuery();
|
|
|
|
|
|
|
|
if (aFolder)
|
|
|
|
query.setFolders([aFolder], 1);
|
2009-12-17 12:59:45 -08:00
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
let result = PlacesUtils.history.executeQuery(query, options);
|
|
|
|
let rootNode = result.root;
|
|
|
|
rootNode.containerOpen = true;
|
2009-10-20 20:32:36 -07:00
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
let cc = rootNode.childCount;
|
|
|
|
for (var i=0; i<cc; ++i) {
|
2009-12-17 12:59:45 -08:00
|
|
|
let node = rootNode.getChild(i);
|
|
|
|
|
|
|
|
// Ignore separators
|
|
|
|
if (node.type == node.RESULT_TYPE_SEPARATOR)
|
|
|
|
continue;
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
if (this._mode == "folders" && node.type == node.RESULT_TYPE_FOLDER) {
|
|
|
|
items.push(node);
|
|
|
|
}
|
|
|
|
else if (this._mode == "") {
|
|
|
|
items.push(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rootNode.containerOpen = false;
|
|
|
|
return items;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
2009-12-09 16:14:40 -08:00
|
|
|
<!-- Number of elements to add to the list initially. If there are more
|
|
|
|
than this many bookmarks to display, only add them to the list once
|
|
|
|
the user has scrolled towards them. This is a performance
|
|
|
|
optimization to avoid locking up while attempting to append hundreds
|
|
|
|
of bookmarks to our richlistbox.
|
|
|
|
-->
|
|
|
|
<field name="batchSize">25</field>
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
<method name="openFolder">
|
|
|
|
<parameter name="aRootFolder"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
2009-11-19 11:40:54 -08:00
|
|
|
aRootFolder = aRootFolder || this.mobileRoot;
|
2009-02-24 22:20:45 -08:00
|
|
|
|
|
|
|
this._activeItem = null;
|
|
|
|
|
|
|
|
let parents = this._parents;
|
|
|
|
while (parents.firstChild)
|
|
|
|
parents.removeChild(parents.firstChild);
|
|
|
|
|
|
|
|
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
let folderId = aRootFolder;
|
|
|
|
do {
|
2009-12-14 12:26:51 -08:00
|
|
|
let title;
|
|
|
|
if (folderId == this._fakeDesktopFolderId)
|
|
|
|
title = this._desktopFolder.title;
|
|
|
|
else
|
|
|
|
title = PlacesUtils.bookmarks.getItemTitle(folderId);
|
2009-04-08 22:40:05 -07:00
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
let parent = document.createElementNS(XULNS, "placelabel");
|
|
|
|
parent.setAttribute("class", "bookmark-folder");
|
|
|
|
parent.setAttribute("itemid", folderId);
|
|
|
|
parent.setAttribute("indent", 0);
|
2009-04-08 22:40:05 -07:00
|
|
|
parent.setAttribute("title", title);
|
2009-02-24 22:20:45 -08:00
|
|
|
parents.insertBefore(parent, parents.firstChild);
|
|
|
|
|
|
|
|
// XXX Fix me - use <handler>?
|
2009-09-11 07:56:09 -07:00
|
|
|
parent.addEventListener("click", function(e) { self.openFolder(e.target.previousSibling.itemId); }, false);
|
2009-12-14 12:26:51 -08:00
|
|
|
|
|
|
|
folderId = this._folderParents[folderId] || PlacesUtils.bookmarks.getFolderIdForItem(folderId);
|
2009-02-24 22:20:45 -08:00
|
|
|
} while (folderId != PlacesUtils.bookmarks.placesRoot)
|
|
|
|
|
|
|
|
let children = this._children;
|
|
|
|
while (children.firstChild)
|
|
|
|
children.removeChild(children.firstChild);
|
|
|
|
|
2009-03-03 06:31:51 -08:00
|
|
|
children.scrollBoxObject.scrollTo(0, 0);
|
|
|
|
|
2009-12-09 16:14:40 -08:00
|
|
|
this._childItems = (aRootFolder == this._fakeDesktopFolderId) ? this._desktopChildren.concat()
|
|
|
|
: this._getChildren(aRootFolder);
|
2009-12-14 12:26:51 -08:00
|
|
|
|
|
|
|
if (aRootFolder == this.mobileRoot && !this.isDesktopFolderEmpty())
|
2009-12-09 16:14:40 -08:00
|
|
|
this._childItems.unshift(this._desktopFolder);
|
|
|
|
|
|
|
|
this._insertItems();
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="close">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
// Clear out references to child items, and remove event listener
|
|
|
|
// if needed
|
|
|
|
this._childItems = null;
|
|
|
|
if (this._scrollListenerAdded) {
|
|
|
|
this._children.removeEventListener("scroll", this._scrollListener, false);
|
|
|
|
this._scrollListenerAdded = false;
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="_insertItems">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
let items = this._childItems.splice(0, this.batchSize);
|
|
|
|
|
|
|
|
if (!items.length)
|
|
|
|
return; // no items to insert
|
|
|
|
|
|
|
|
let children = this._children;
|
|
|
|
let itemsRemaining = this._childItems.length > 0;
|
|
|
|
if (itemsRemaining && !this._scrollListenerAdded) {
|
|
|
|
// We're not going to insert all items, so add a scroll listener
|
|
|
|
// to know when to add them.
|
|
|
|
this._children.addEventListener("scroll", this._scrollListener, false);
|
|
|
|
this._scrollListenerAdded = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!itemsRemaining && this._scrollListenerAdded) {
|
|
|
|
// Can get rid of the scroll listener now that all items are added.
|
|
|
|
this._children.removeEventListener("scroll", this._scrollListener, false);
|
|
|
|
this._scrollListenerAdded = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let fragment = document.createDocumentFragment();
|
|
|
|
let count = items.length;
|
2009-11-23 08:44:34 -08:00
|
|
|
for (let i=0; i<count; i++)
|
2009-12-09 16:14:40 -08:00
|
|
|
fragment.appendChild(this.createItem(items[i]));
|
2009-11-23 08:44:34 -08:00
|
|
|
children.appendChild(fragment);
|
2009-12-09 16:14:40 -08:00
|
|
|
|
|
|
|
// make sure we recalculate the scrollHeight of the children
|
|
|
|
this._childrenScrollHeight = -1;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<field name="_scrollListener"><![CDATA[
|
|
|
|
({
|
|
|
|
self: this,
|
|
|
|
handleEvent: function () {
|
|
|
|
this.self._checkForInsert();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
]]></field>
|
|
|
|
|
|
|
|
<method name="_checkForInsert">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (this._childrenScrollHeight == -1) {
|
|
|
|
// Need to force a reflow to get the right value here since we may
|
|
|
|
// have just added children.
|
|
|
|
Browser.forceChromeReflow();
|
|
|
|
let scrollheight = {};
|
|
|
|
this.scrollBoxObject.getScrolledSize({}, scrollheight);
|
|
|
|
this._childrenScrollHeight = scrollheight.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
let y = {};
|
|
|
|
this.scrollBoxObject.getPosition({}, y);
|
|
|
|
let scrollRatio = (y.value + this._childrenHeight) / this._childrenScrollHeight;
|
|
|
|
|
|
|
|
// If we're scrolled 80% to the bottom of the list, append the next
|
|
|
|
// set of items
|
|
|
|
if (scrollRatio > 0.8)
|
|
|
|
this._insertItems();
|
2009-02-24 22:20:45 -08:00
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
2009-04-08 22:40:05 -07:00
|
|
|
<method name="createItem">
|
|
|
|
<parameter name="aItem"/>
|
2009-02-24 22:20:45 -08:00
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|
|
|
|
|
|
|
let child = document.createElementNS(XULNS, "placeitem");
|
2009-04-08 22:40:05 -07:00
|
|
|
child.setAttribute("itemid", aItem.itemId);
|
2009-02-24 22:20:45 -08:00
|
|
|
child.setAttribute("class", "bookmark-item");
|
2009-04-08 22:40:05 -07:00
|
|
|
child.setAttribute("title", aItem.title);
|
|
|
|
child.setAttribute("uri", aItem.uri);
|
|
|
|
child.setAttribute("tags", aItem.tags);
|
|
|
|
if (aItem.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER)
|
2009-02-24 22:20:45 -08:00
|
|
|
child.setAttribute("type", "folder");
|
2009-11-23 08:44:34 -08:00
|
|
|
else
|
|
|
|
child.setAttribute("src", aItem.icon);
|
2009-02-24 22:20:45 -08:00
|
|
|
|
2009-09-09 21:24:55 -07:00
|
|
|
// XXX make a <handler>
|
2009-11-23 08:44:34 -08:00
|
|
|
let self = this;
|
2009-09-09 21:24:55 -07:00
|
|
|
child.addEventListener("click", function(e) { self._fireOpen(e, child); }, false);
|
2009-02-24 22:20:45 -08:00
|
|
|
|
|
|
|
return child;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="removeItem">
|
|
|
|
<parameter name="aItem"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
this._children.removeChild(aItem);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="_fireOpen">
|
|
|
|
<parameter name="aEvent"/>
|
|
|
|
<parameter name="aItem"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
2009-09-09 18:47:37 -07:00
|
|
|
if (aEvent.originalTarget.localName == "button" || this._activeItem == aItem)
|
2009-02-24 22:20:45 -08:00
|
|
|
return;
|
|
|
|
|
2009-09-09 18:47:37 -07:00
|
|
|
if (this._manageUI) {
|
|
|
|
aItem.startEditing();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-24 22:20:45 -08:00
|
|
|
if (aItem.type == "folder") {
|
|
|
|
this.openFolder(aItem.itemId);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Force the item to be active
|
|
|
|
this._activeItem = aItem;
|
|
|
|
|
|
|
|
// This is a callback used to forward information to some
|
|
|
|
// external code [we fire an event & a pseudo attribute event]
|
|
|
|
let event = document.createEvent("Events");
|
|
|
|
event.initEvent("BookmarkOpen", true, false);
|
|
|
|
this.dispatchEvent(event);
|
|
|
|
let func = new Function("event", this.getAttribute("onopen"));
|
|
|
|
func.call(this, event);
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
</binding>
|
|
|
|
|
2009-09-11 06:26:42 -07:00
|
|
|
<binding id="richlistitem" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
|
|
|
|
<handlers>
|
|
|
|
<handler event="mousedown" phase="capturing">
|
|
|
|
<![CDATA[
|
|
|
|
event.stopPropagation();
|
|
|
|
]]>
|
|
|
|
</handler>
|
|
|
|
</handlers>
|
|
|
|
</binding>
|
|
|
|
|
2009-09-17 13:17:57 -07:00
|
|
|
<binding id="menulist" display="xul:box" extends="chrome://global/content/bindings/menulist.xml#menulist">
|
|
|
|
<handlers>
|
|
|
|
<handler event="mousedown" phase="capturing">
|
|
|
|
<![CDATA[
|
|
|
|
// Stop the normal menupopup from appearing
|
|
|
|
event.stopPropagation();
|
|
|
|
]]>
|
|
|
|
</handler>
|
|
|
|
|
|
|
|
<handler event="click" button="0">
|
|
|
|
<![CDATA[
|
|
|
|
if (this.disabled || this.itemCount == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.focus();
|
|
|
|
SelectHelper.show(this);
|
|
|
|
]]>
|
|
|
|
</handler>
|
|
|
|
</handlers>
|
|
|
|
</binding>
|
|
|
|
|
2009-06-24 09:42:53 -07:00
|
|
|
<binding id="chrome-select-option">
|
2009-07-06 10:14:46 -07:00
|
|
|
<content orient="horizontal" flex="1">
|
2009-06-24 09:42:53 -07:00
|
|
|
<xul:image anonid="check"/>
|
|
|
|
<xul:label anonid="label" xbl:inherits="value=label"/>
|
|
|
|
</content>
|
|
|
|
|
|
|
|
<implementation>
|
|
|
|
<property name="selected">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
return this.hasAttribute("selected");
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
|
|
|
if (val)
|
|
|
|
this.setAttribute("selected", "true");
|
|
|
|
else
|
|
|
|
this.removeAttribute("selected");
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
</implementation>
|
|
|
|
</binding>
|
2008-07-16 08:41:38 -07:00
|
|
|
</bindings>
|