зеркало из https://github.com/mozilla/pjs.git
Bug 385266 - New starring, bookmarking and tagging UI. This is work-in-progress and not yet enabled for anything but the star button itself. Smart folders are not yet hooked up either. r=dietrich.
This commit is contained in:
Родитель
a8f167dbc2
Коммит
35a4df2896
|
@ -592,3 +592,141 @@ var PlacesMenuDNDController = {
|
|||
_dragSupported: true
|
||||
#endif
|
||||
};
|
||||
|
||||
var PlacesStarButton = {
|
||||
init: function PSB_init() {
|
||||
PlacesUtils.bookmarks.addObserver(this, false);
|
||||
},
|
||||
|
||||
uninit: function PSB_uninit() {
|
||||
PlacesUtils.bookmarks.removeObserver(this);
|
||||
},
|
||||
|
||||
QueryInterface: function PSB_QueryInterface(aIID) {
|
||||
if (aIID.equals(Ci.nsIDOMEventListener) ||
|
||||
aIID.equals(Ci.nsINavBookmarkObserver) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Cr.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
get panel() {
|
||||
return document.getElementById("editBookmarkPanel");
|
||||
},
|
||||
|
||||
_starred: false,
|
||||
_batching: false,
|
||||
|
||||
updateState: function PSB_updateState() {
|
||||
var uri = getBrowser().currentURI;
|
||||
this._starred = uri && PlacesUtils.bookmarks.isBookmarked(uri);
|
||||
if (this._starred)
|
||||
document.getElementById("star-icon").setAttribute("starred", "true");
|
||||
else
|
||||
document.getElementById("star-icon").removeAttribute("starred");
|
||||
},
|
||||
|
||||
_star: function PSB_star(aBrowser) {
|
||||
var uri = aBrowser.currentURI;
|
||||
if (!uri)
|
||||
throw "No URL";
|
||||
|
||||
var title = PlacesUtils.history.getPageTitle(uri);
|
||||
|
||||
var descAnno = {
|
||||
name: DESCRIPTION_ANNO,
|
||||
value: PlacesUtils.getDescriptionFromDocument(aBrowser.contentDocument)
|
||||
};
|
||||
var txn = PlacesUtils.ptm.createItem(uri, PlacesUtils.placesRootId, -1,
|
||||
title, null, [descAnno]);
|
||||
PlacesUtils.ptm.commitTransaction(txn);
|
||||
},
|
||||
|
||||
// nsIDOMEventListener
|
||||
handleEvent: function PSB_handleEvent(aEvent) {
|
||||
if (aEvent.originalTarget != this.panel)
|
||||
return;
|
||||
|
||||
// This only happens for auto-hide. When the panel is closed from within
|
||||
// itself, doneCallback removes the listener and only then hides the popup
|
||||
gAddBookmarksPanel.saveItem();
|
||||
gAddBookmarksPanel.uninitPanel();
|
||||
},
|
||||
|
||||
showBookmarkPagePopup: function PSB_showBookmarkPagePopup(aBrowser) {
|
||||
const bms = PlacesUtils.bookmarks;
|
||||
|
||||
var dockTo = document.getElementById("star-icon");
|
||||
if (!dockTo)
|
||||
dockTo = getBrowser();
|
||||
|
||||
var panel = this.panel;
|
||||
panel.showPopup(dockTo, -1, -1, "popup", "bottomright", "topright");
|
||||
|
||||
var uri = aBrowser.currentURI;
|
||||
|
||||
var itemId = -1;
|
||||
var bmkIds = bms.getBookmarkIdsForURI(uri, {});
|
||||
for each (var bk in bmkIds) {
|
||||
// Find the first folder which isn't a tag container
|
||||
var folder = bms.getFolderIdForItem(bk);
|
||||
if (folder == PlacesUtils.placesRootId ||
|
||||
bms.getFolderIdForItem(folder) != PlacesUtils.tagRootId) {
|
||||
itemId = bk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (itemId == -1) {
|
||||
// if we're called before the URI is bookmarked, or if the remaining
|
||||
// items for this url are under tag containers, star the page first
|
||||
itemId = this._star(aBrowser);
|
||||
}
|
||||
gAddBookmarksPanel.initPanel(itemId, PlacesUtils.tm, this.doneCallback,
|
||||
{ hiddenRows: "description" });
|
||||
panel.addEventListener("popuphiding", this, false);
|
||||
},
|
||||
|
||||
onClick: function PSB_onClick(aEvent) {
|
||||
if (this._starred)
|
||||
this.showBookmarkPagePopup(getBrowser());
|
||||
else
|
||||
this._star(getBrowser());
|
||||
},
|
||||
|
||||
doneCallback: function PSB_doneCallback(aSavedChanges) {
|
||||
var panel = PlacesStarButton.panel;
|
||||
panel.removeEventListener("popuphiding", PlacesStarButton, false);
|
||||
gAddBookmarksPanel.uninitPanel();
|
||||
panel.hidePopup();
|
||||
},
|
||||
|
||||
// nsINavBookmarkObserver
|
||||
onBeginUpdateBatch: function PSB_onBeginUpdateBatch() {
|
||||
this._batching = true;
|
||||
},
|
||||
|
||||
onEndUpdateBatch: function PSB_onEndUpdateBatch() {
|
||||
this.updateState();
|
||||
this._batching = false;
|
||||
},
|
||||
|
||||
onItemAdded: function PSB_onItemAdded(aItemId, aFolder, aIndex) {
|
||||
if (!this._batching && !this._starred)
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex) {
|
||||
if (!this._batching)
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
onItemChanged: function PSB_onItemChanged(aItemId, aProperty,
|
||||
aIsAnnotationProperty, aValue) {
|
||||
if (!this._batching && aProperty == "uri")
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
onItemVisited: function() { },
|
||||
onItemMoved: function() { }
|
||||
};
|
||||
|
|
|
@ -1017,6 +1017,7 @@ function delayedStartup()
|
|||
|
||||
initBookmarksToolbar();
|
||||
PlacesUtils.bookmarks.addObserver(gBookmarksObserver, false);
|
||||
PlacesStarButton.init();
|
||||
|
||||
// called when we go into full screen, even if it is
|
||||
// initiated by a web page script
|
||||
|
@ -1157,6 +1158,7 @@ function BrowserShutdown()
|
|||
}
|
||||
|
||||
PlacesUtils.bookmarks.removeObserver(gBookmarksObserver);
|
||||
PlacesStarButton.uninit();
|
||||
|
||||
try {
|
||||
gPrefService.removeObserver(gAutoHideTabbarPrefListener.domain,
|
||||
|
@ -3519,6 +3521,9 @@ nsBrowserStatusHandler.prototype =
|
|||
gURLBar.value = userTypedValue;
|
||||
SetPageProxyState("invalid");
|
||||
}
|
||||
|
||||
// Update starring UI
|
||||
PlacesStarButton.updateState(aLocationURI);
|
||||
}
|
||||
}
|
||||
UpdateBackForwardCommands(gBrowser.webNavigation);
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
|
||||
|
||||
# All DTD information is stored in a separate file so that it can be shared by
|
||||
# hiddenWindow.xul.
|
||||
|
@ -100,6 +101,11 @@
|
|||
|
||||
<panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete" noautofocus="true"/>
|
||||
|
||||
<panel id="editBookmarkPanel"
|
||||
position="after_end">
|
||||
<vbox id="editBookmarkPanelContent" flex="1"/>
|
||||
</panel>
|
||||
|
||||
<popup id="toolbar-context-menu"
|
||||
onpopupshowing="onViewToolbarsPopupShowing(event);">
|
||||
<menuseparator/>
|
||||
|
@ -249,6 +255,7 @@
|
|||
level="safe"
|
||||
onclick="goDoCommand('safebrowsing-show-warning')" />
|
||||
#endif
|
||||
<image id="star-icon" onclick="if (event.button == 0) PlacesStarButton.onClick(event);"/>
|
||||
</hbox>
|
||||
</textbox>
|
||||
<stack id="go-button-stack">
|
||||
|
|
|
@ -0,0 +1,581 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Places Bookmark Properties dialog.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Asaf Romano <mano@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const LAST_USED_ANNO = "bookmarkPropertiesDialog/lastUsed";
|
||||
const MAX_FOLDER_ITEM_IN_MENU_LIST = 5;
|
||||
|
||||
var gAddBookmarksPanel = {
|
||||
/**
|
||||
* The Microsummary Service for displaying microsummaries.
|
||||
*/
|
||||
__mss: null,
|
||||
get _mss() {
|
||||
if (!this.__mss)
|
||||
this.__mss = Cc["@mozilla.org/microsummary/service;1"].
|
||||
getService(Ci.nsIMicrosummaryService);
|
||||
return this.__mss;
|
||||
},
|
||||
|
||||
_uri: null,
|
||||
_itemId: -1,
|
||||
_itemType: -1,
|
||||
_microsummaries: null,
|
||||
_doneCallback: null,
|
||||
_currentTags: [],
|
||||
_hiddenRows: [],
|
||||
|
||||
/**
|
||||
* Determines the initial data for the item edited or added by this dialog
|
||||
*/
|
||||
_determineInfo: function ABP__determineInfo(aInfo) {
|
||||
const bms = PlacesUtils.bookmarks;
|
||||
this._itemType = bms.getItemType(this._itemId);
|
||||
if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK)
|
||||
this._currentTags = PlacesUtils.tagging.getTagsForURI(this._uri);
|
||||
else
|
||||
this._currentTags.splice(0);
|
||||
|
||||
// hidden rows
|
||||
if (aInfo && aInfo.hiddenRows)
|
||||
this._hiddenRows = aInfo.hiddenRows;
|
||||
else
|
||||
this._hiddenRows.splice(0);
|
||||
},
|
||||
|
||||
_showHideRows: function EBP__showHideRows() {
|
||||
this._element("nameRow").hidden = this._hiddenRows.indexOf("name") != -1;
|
||||
this._element("folderRow").hidden =
|
||||
this._hiddenRows.indexOf("folderPicker") != -1;
|
||||
this._element("tagsRow").hidden = this._hiddenRows.indexOf("tags") != -1 ||
|
||||
this._itemType != Ci.nsINavBookmarksService.TYPE_BOOKMARK;
|
||||
this._element("descriptionRow").hidden =
|
||||
this._hiddenRows.indexOf("description") != -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the panel
|
||||
*/
|
||||
initPanel: function ABP_initPanel(aItemId, aTm, aDoneCallback, aInfo) {
|
||||
this._folderMenuList = this._element("folderMenuList");
|
||||
this._folderTree = this._element("folderTree");
|
||||
this._tm = aTm;
|
||||
this._itemId = aItemId;
|
||||
this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
|
||||
this._doneCallback = aDoneCallback;
|
||||
this._determineInfo(aInfo);
|
||||
|
||||
// folder picker
|
||||
this._initFolderMenuList();
|
||||
|
||||
// name picker
|
||||
this._initNamePicker();
|
||||
|
||||
// tags field
|
||||
this._element("tagsField").value = this._currentTags.join(", ");
|
||||
|
||||
// description field
|
||||
this._element("descriptionField").value =
|
||||
PlacesUtils.getItemDescription(this._itemId);
|
||||
|
||||
this._showHideRows();
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends a menu-item representing a bookmarks folder to a menu-popup.
|
||||
* @param aMenupopup
|
||||
* The popup to which the menu-item should be added.
|
||||
* @param aFolderId
|
||||
* The identifier of the bookmarks folder.
|
||||
* @return the new menu item.
|
||||
*/
|
||||
_appendFolderItemToMenupopup:
|
||||
function BPP__appendFolderItemToMenuList(aMenupopup, aFolderId) {
|
||||
// First make sure the folders-separator is visible
|
||||
this._element("foldersSeparator").hidden = false;
|
||||
|
||||
var folderMenuItem = document.createElement("menuitem");
|
||||
var folderTitle = PlacesUtils.bookmarks.getItemTitle(aFolderId)
|
||||
folderMenuItem.folderId = aFolderId;
|
||||
folderMenuItem.setAttribute("label", folderTitle);
|
||||
folderMenuItem.className = "menuitem-iconic folder-icon";
|
||||
aMenupopup.appendChild(folderMenuItem);
|
||||
return folderMenuItem;
|
||||
},
|
||||
|
||||
_initFolderMenuList: function BPP__initFolderMenuList() {
|
||||
// clean up first
|
||||
var menupopup = this._folderMenuList.menupopup;
|
||||
while (menupopup.childNodes.length > 4)
|
||||
menupopup.removeChild(menupopup.lastChild);
|
||||
|
||||
var container = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId);
|
||||
|
||||
// only show "All Bookmarks" if the url isn't bookmarked somewhere else
|
||||
this._element("placesRootItem").hidden = container != PlacesUtils.placesRootId;
|
||||
|
||||
// List of recently used folders:
|
||||
var annos = PlacesUtils.annotations;
|
||||
var folderIds = annos.getItemsWithAnnotation(LAST_USED_ANNO, { });
|
||||
|
||||
/**
|
||||
* The value of the LAST_USED_ANNO annotation is the time (in the form of
|
||||
* Date.getTime) at which the folder has been last used.
|
||||
*
|
||||
* First we build the annotated folders array, each item has both the
|
||||
* folder identifier and the time at which it was last-used by this dialog
|
||||
* set. Then we sort it descendingly based on the time field.
|
||||
*/
|
||||
var folders = [];
|
||||
for (var i=0; i < folderIds.length; i++) {
|
||||
var lastUsed = annos.getItemAnnotation(folderIds[i], LAST_USED_ANNO);
|
||||
folders.push({ folderId: folderIds[i], lastUsed: lastUsed });
|
||||
}
|
||||
folders.sort(function(a, b) {
|
||||
if (b.lastUsed < a.lastUsed)
|
||||
return -1;
|
||||
if (b.lastUsed > a.lastUsed)
|
||||
return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
var numberOfItems = Math.min(MAX_FOLDER_ITEM_IN_MENU_LIST, folders.length);
|
||||
for (i=0; i < numberOfItems; i++) {
|
||||
this._appendFolderItemToMenupopup(menupopup, folders[i].folderId);
|
||||
}
|
||||
|
||||
var defaultItem = this._getFolderMenuItem(container, true);
|
||||
this._folderMenuList.selectedItem = defaultItem;
|
||||
|
||||
// Hide the folders-separator if no folder is annotated as recently-used
|
||||
this._element("foldersSeparator").hidden = (menupopup.childNodes.length <= 4);
|
||||
},
|
||||
|
||||
QueryInterface: function BPP_QueryInterface(aIID) {
|
||||
if (aIID.equals(Ci.nsIMicrosummaryObserver) ||
|
||||
aIID.equals(Ci.nsIDOMEventListener) ||
|
||||
aIID.eqauls(Ci.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
_element: function BPP__element(aID) {
|
||||
return document.getElementById("editBMPanel_" + aID);
|
||||
},
|
||||
|
||||
_createMicrosummaryMenuItem:
|
||||
function BPP__createMicrosummaryMenuItem(aMicrosummary) {
|
||||
var menuItem = document.createElement("menuitem");
|
||||
|
||||
// Store a reference to the microsummary in the menu item, so we know
|
||||
// which microsummary this menu item represents when it's time to
|
||||
// save changes or load its content.
|
||||
menuItem.microsummary = aMicrosummary;
|
||||
|
||||
// Content may have to be generated asynchronously; we don't necessarily
|
||||
// have it now. If we do, great; otherwise, fall back to the generator
|
||||
// name, then the URI, and we trigger a microsummary content update. Once
|
||||
// the update completes, the microsummary will notify our observer to
|
||||
// update the corresponding menu-item.
|
||||
// XXX Instead of just showing the generator name or (heaven forbid)
|
||||
// its URI when we don't have content, we should tell the user that
|
||||
// we're loading the microsummary, perhaps with some throbbing to let
|
||||
// her know it is in progress.
|
||||
if (aMicrosummary.content)
|
||||
menuItem.setAttribute("label", aMicrosummary.content);
|
||||
else {
|
||||
menuItem.setAttribute("label", aMicrosummary.generator.name ||
|
||||
aMicrosummary.generator.uri.spec);
|
||||
aMicrosummary.update();
|
||||
}
|
||||
|
||||
return menuItem;
|
||||
},
|
||||
|
||||
_initNamePicker: function ABP_initNamePicker() {
|
||||
var userEnteredNameField = this._element("userEnteredName");
|
||||
var namePicker = this._element("namePicker");
|
||||
var droppable = false;
|
||||
|
||||
userEnteredNameField.label =
|
||||
PlacesUtils.bookmarks.getItemTitle(this._itemId);
|
||||
|
||||
// clean up old entries
|
||||
var menupopup = namePicker.menupopup;
|
||||
while (menupopup.childNodes.length > 2)
|
||||
menupopup.removeChild(menupopup.lastChild);
|
||||
|
||||
var itemToSelect = userEnteredNameField;
|
||||
try {
|
||||
this._microsummaries = this._mss.getMicrosummaries(this._uri, -1);
|
||||
}
|
||||
catch(ex) {
|
||||
// getMicrosummaries will throw an exception in at least two cases:
|
||||
// 1. the bookmarked URI contains a scheme that the service won't
|
||||
// download for security reasons (currently it only handles http,
|
||||
// https, and file);
|
||||
// 2. the page to which the URI refers isn't HTML or XML (the only two
|
||||
// content types the service knows how to summarize).
|
||||
this._microsummaries = null;
|
||||
}
|
||||
if (this._microsummaries) {
|
||||
var enumerator = this._microsummaries.Enumerate();
|
||||
|
||||
if (enumerator.hasMoreElements()) {
|
||||
// Show the drop marker if there are microsummaries
|
||||
droppable = true;
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var microsummary = enumerator.getNext()
|
||||
.QueryInterface(Ci.nsIMicrosummary);
|
||||
var menuItem = this._createMicrosummaryMenuItem(microsummary);
|
||||
menupopup.appendChild(menuItem);
|
||||
}
|
||||
}
|
||||
|
||||
this._microsummaries.addObserver(this);
|
||||
}
|
||||
|
||||
if (namePicker.selectedItem == itemToSelect)
|
||||
namePicker.value = itemToSelect.label;
|
||||
else
|
||||
namePicker.selectedItem = itemToSelect;
|
||||
|
||||
namePicker.setAttribute("droppable", droppable);
|
||||
},
|
||||
|
||||
// nsIMicrosummaryObserver
|
||||
onContentLoaded: function ABP_onContentLoaded(aMicrosummary) {
|
||||
var namePicker = this._element("namePicker");
|
||||
var childNodes = namePicker.menupopup.childNodes;
|
||||
|
||||
// 0: user-entered item; 1: separator
|
||||
for (var i = 2; i < childNodes.length; i++) {
|
||||
if (childNodes[i].microsummary == aMicrosummary) {
|
||||
var newLabel = aMicrosummary.content;
|
||||
// XXXmano: non-editable menulist would do this for us, see bug 360220
|
||||
// We should fix editable-menulists to set the DOMAttrModified handler
|
||||
// as well.
|
||||
//
|
||||
// Also note the order importance: if the label of the menu-item is
|
||||
// set to something different than the menulist's current value,
|
||||
// the menulist no longer has selectedItem set
|
||||
if (namePicker.selectedItem == childNodes[i])
|
||||
namePicker.value = newLabel;
|
||||
|
||||
childNodes[i].label = newLabel;
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onElementAppended: function BPP_onElementAppended(aMicrosummary) {
|
||||
var namePicker = this._element("namePicker");
|
||||
namePicker.menupopup
|
||||
.appendChild(this._createMicrosummaryMenuItem(aMicrosummary));
|
||||
|
||||
// Make sure the drop-marker is shown
|
||||
namePicker.setAttribute("droppable", "true");
|
||||
},
|
||||
|
||||
uninitPanel: function ABP_uninitPanel() {
|
||||
if (this._microsummaries)
|
||||
this._microsummaries.removeObserver(this);
|
||||
|
||||
// hide the folder tree if it was previously visible
|
||||
if (!this._folderTree.collapsed)
|
||||
this.toggleFolderTreeVisibility();
|
||||
|
||||
// hide the tag selector if it was previously visible
|
||||
var tagsSelector = this._element("tagsSelector");
|
||||
if (!tagsSelector.collapsed)
|
||||
tagsSelector.collapsed = true;
|
||||
},
|
||||
|
||||
saveItem: function ABP_saveItem() {
|
||||
var container = this._getFolderIdFromMenuList();
|
||||
const bms = PlacesUtils.bookmarks;
|
||||
const ptm = PlacesUtils.ptm;
|
||||
var txns = [];
|
||||
|
||||
// container
|
||||
if (bms.getFolderIdForItem(this._itemId) != container)
|
||||
txns.push(ptm.moveItem(this._itemId, container, -1));
|
||||
|
||||
// title
|
||||
var newTitle = this._element("userEnteredName").label;
|
||||
if (bms.getItemTitle(this._itemId) != newTitle)
|
||||
txns.push(ptm.editItemTitle(this._itemId, newTitle));
|
||||
|
||||
// description
|
||||
var newDescription = this._element("descriptionField").value;
|
||||
if (newDescription != PlacesUtils.getItemDescription(this._itemId))
|
||||
txns.push(ptm.editItemDescription(this._itemId, newDescription));
|
||||
|
||||
// Tags, NOT YET UNDOABLE
|
||||
var tags = this._getTagsArrayFromTagField();
|
||||
if (tags.length > 0 || this._currentTags.length > 0) {
|
||||
var tagsToRemove = [];
|
||||
var tagsToAdd = [];
|
||||
var t;
|
||||
for each (t in this._currentTags) {
|
||||
if (tags.indexOf(t) == -1)
|
||||
tagsToRemove.push(t);
|
||||
}
|
||||
for each (t in tags) {
|
||||
if (this._currentTags.indexOf(t) == -1)
|
||||
tagsToAdd.push(t);
|
||||
}
|
||||
|
||||
if (tagsToAdd.length > 0)
|
||||
PlacesUtils.tagging.tagURI(this._uri, tagsToAdd);
|
||||
if (tagsToRemove.length > 0)
|
||||
PlacesUtils.tagging.untagURI(this._uri, tagsToRemove);
|
||||
}
|
||||
|
||||
if (txns.length > 0) {
|
||||
// Mark the containing folder as recently-used if it isn't the
|
||||
// "All Bookmarks" root
|
||||
if (container != PlacesUtils.placesRootId)
|
||||
this._markFolderAsRecentlyUsed(container);
|
||||
}
|
||||
|
||||
if (txns.length > 0)
|
||||
ptm.commitTransaction(ptm.aggregateTransactions("Edit Item", txns));
|
||||
},
|
||||
|
||||
onNamePickerInput: function ABP_onNamePickerInput() {
|
||||
this._element("userEnteredName").label = this._element("namePicker").value;
|
||||
},
|
||||
|
||||
toggleFolderTreeVisibility: function ABP_toggleFolderTreeVisibility() {
|
||||
var expander = this._element("foldersExpander");
|
||||
if (!this._folderTree.collapsed) {
|
||||
expander.className = "expander-down";
|
||||
expander.setAttribute("tooltiptext",
|
||||
expander.getAttribute("tooltiptextdown"));
|
||||
this._folderTree.collapsed = true;
|
||||
}
|
||||
else {
|
||||
expander.className = "expander-up"
|
||||
expander.setAttribute("tooltiptext",
|
||||
expander.getAttribute("tooltiptextup"));
|
||||
if (!this._folderTree.treeBoxObject.view.isContainerOpen(0))
|
||||
this._folderTree.treeBoxObject.view.toggleOpenState(0);
|
||||
this._folderTree.selectFolders([this._getFolderIdFromMenuList()]);
|
||||
this._folderTree.collapsed = false;
|
||||
this._folderTree.focus();
|
||||
}
|
||||
},
|
||||
|
||||
_getFolderIdFromMenuList:
|
||||
function BPP__getFolderIdFromMenuList() {
|
||||
var selectedItem = this._folderMenuList.selectedItem
|
||||
switch (selectedItem.id) {
|
||||
case "editBMPanel_placesRootItem":
|
||||
return PlacesUtils.placesRootId;
|
||||
case "editBMPanel_bmRootItem":
|
||||
return PlacesUtils.bookmarksRootId;
|
||||
case "editBMPanel_toolbarFolderItem":
|
||||
return PlacesUtils.toolbarFolderId;
|
||||
}
|
||||
|
||||
NS_ASSERT("folderId" in selectedItem,
|
||||
"Invalid menuitem in the folders-menulist");
|
||||
return selectedItem.folderId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the corresponding menu-item in the folder-menu-list for a bookmarks
|
||||
* folder if such an item exists. Otherwise, this creates a menu-item for the
|
||||
* folder. If the items-count limit (see MAX_FOLDERS_IN_MENU_LIST) is reached,
|
||||
* the new item replaces the last menu-item.
|
||||
* @param aFolderId
|
||||
* The identifier of the bookmarks folder
|
||||
* @param aCheckStaticFolderItems
|
||||
* whether or not to also treat the static items at the top of
|
||||
* menu-list. Note dynamic items get precedence even if this is set to
|
||||
* true.
|
||||
*/
|
||||
_getFolderMenuItem:
|
||||
function BPP__getFolderMenuItem(aFolderId, aCheckStaticFolderItems) {
|
||||
var menupopup = this._folderMenuList.menupopup;
|
||||
|
||||
// 0: All Bookmarks, 1: Bookmarks root, 2: toolbar folder, 3: separator
|
||||
for (var i=4; i < menupopup.childNodes.length; i++) {
|
||||
if (menupopup.childNodes[i].folderId == aFolderId)
|
||||
return menupopup.childNodes[i];
|
||||
}
|
||||
|
||||
if (aCheckStaticFolderItems) {
|
||||
if (aFolderId == PlacesUtils.placesRootId)
|
||||
return this._element("placesRootItem");
|
||||
if (aFolderId == PlacesUtils.bookmarksRootId)
|
||||
return this._element("bmRootItem")
|
||||
if (aFolderId == PlacesUtils.toolbarFolderId)
|
||||
return this._element("toolbarFolderItem")
|
||||
}
|
||||
|
||||
// 3 special folders + separator + folder-items-count limit
|
||||
if (menupopup.childNodes.length == 4 + MAX_FOLDER_ITEM_IN_MENU_LIST)
|
||||
menupopup.removeChild(menupopup.lastChild);
|
||||
|
||||
return this._appendFolderItemToMenupopup(menupopup, aFolderId);
|
||||
},
|
||||
|
||||
onMenuListFolderSelect: function BPP_onMenuListFolderSelect(aEvent) {
|
||||
if (this._folderTree.hidden)
|
||||
return;
|
||||
|
||||
this._folderTree.selectFolders([this._getFolderIdFromMenuList()]);
|
||||
},
|
||||
|
||||
onFolderTreeSelect: function BPP_onFolderTreeSelect() {
|
||||
var selectedNode = this._folderTree.selectedNode;
|
||||
if (!selectedNode)
|
||||
return;
|
||||
|
||||
var folderId = selectedNode.itemId;
|
||||
// Don't set the selected item if the static item for the folder is
|
||||
// already selected
|
||||
var oldSelectedItem = this._folderMenuList.selectedItem;
|
||||
if ((oldSelectedItem.id == "editBMPanel_toolbarFolderItem" &&
|
||||
folderId == PlacesUtils.bookmarks.toolbarFolder) ||
|
||||
(oldSelectedItem.id == "editBMPanel_bmRootItem" &&
|
||||
folderId == PlacesUtils.bookmarks.bookmarksRoot))
|
||||
return;
|
||||
|
||||
var folderItem = this._getFolderMenuItem(folderId, false);
|
||||
this._folderMenuList.selectedItem = folderItem;
|
||||
},
|
||||
|
||||
_markFolderAsRecentlyUsed:
|
||||
function ABP__markFolderAsRecentlyUsed(aFolderId) {
|
||||
// We'll figure out when/if to expire the annotation if it turns out
|
||||
// we keep this recently-used-folders implementation
|
||||
PlacesUtils.annotations
|
||||
.setItemAnnotation(aFolderId, LAST_USED_ANNO,
|
||||
new Date().getTime(), 0,
|
||||
Ci.nsIAnnotationService.EXPIRE_NEVER);
|
||||
},
|
||||
|
||||
accept: function ABP_accept() {
|
||||
this.saveItem();
|
||||
if (typeof(this._doneCallback) == "function")
|
||||
this._doneCallback();
|
||||
},
|
||||
|
||||
deleteAndClose: function ABP_deleteAndClose() {
|
||||
// remove the item
|
||||
if (this._itemId != -1)
|
||||
PlacesUtils.bookmarks.removeItem(this._itemId);
|
||||
|
||||
// remove all tags for the associated url
|
||||
PlacesUtils.tagging.untagURI(this._uri, null);
|
||||
|
||||
if (typeof(this._doneCallback) == "function")
|
||||
this._doneCallback();
|
||||
},
|
||||
|
||||
toggleTagsSelector: function ABP_toggleTagsSelector() {
|
||||
var tagsSelector = this._element("tagsSelector");
|
||||
var expander = this._element("tagsSelectorExpander");
|
||||
if (tagsSelector.collapsed) {
|
||||
expander.className = "expander-down";
|
||||
expander.setAttribute("tooltiptext",
|
||||
expander.getAttribute("tooltiptextdown"));
|
||||
|
||||
// rebuild the tag list
|
||||
while (tagsSelector.hasChildNodes())
|
||||
tagsSelector.removeChild(tagsSelector.lastChild);
|
||||
|
||||
var tagsInField = this._getTagsArrayFromTagField();
|
||||
var allTags = PlacesUtils.tagging.allTags;
|
||||
for each (var tag in allTags) {
|
||||
var elt = document.createElement("listitem");
|
||||
elt.setAttribute("type", "checkbox");
|
||||
elt.setAttribute("label", tag);
|
||||
if (tagsInField.indexOf(tag) != -1)
|
||||
elt.setAttribute("checked", "true");
|
||||
|
||||
tagsSelector.appendChild(elt);
|
||||
}
|
||||
|
||||
// This is a no-op if we've added the listener.
|
||||
tagsSelector.addEventListener("CheckboxStateChange", this, false);
|
||||
}
|
||||
else {
|
||||
expander.className = "expander-down";
|
||||
expander.setAttribute("tooltiptext",
|
||||
expander.getAttribute("tooltiptextdown"));
|
||||
}
|
||||
|
||||
tagsSelector.collapsed = !tagsSelector.collapsed;
|
||||
},
|
||||
|
||||
_getTagsArrayFromTagField: function() {
|
||||
// we don't require the leading space (after each comma)
|
||||
var tags = this._element("tagsField").value.split(",");
|
||||
for (var i=0; i < tags.length; i++) {
|
||||
// remove trailing and leading spaces
|
||||
tags[i] = tags[i].replace(/^\s+/, "").replace(/\s+$/, "");
|
||||
|
||||
// remove empty entries from the array.
|
||||
if (tags[i] == "") {
|
||||
tags.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
},
|
||||
|
||||
// nsIDOMEventListener
|
||||
handleEvent: function ABP_nsIDOMEventListener(aEvent) {
|
||||
if (aEvent.type == "CheckboxStateChange") {
|
||||
// Update the tags field when items are checked/unchecked in the listbox
|
||||
var tags = this._getTagsArrayFromTagField();
|
||||
|
||||
if (aEvent.target.checked)
|
||||
tags.push(aEvent.target.label);
|
||||
else {
|
||||
var indexOfItem = tags.indexOf(aEvent.target.label);
|
||||
if (indexOfItem != -1)
|
||||
tags.splice(indexOfItem, 1);
|
||||
}
|
||||
this._element("tagsField").value = tags.join(", ");
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,150 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is the Places Edit Bookmarks Panel code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Asaf Romano <mano@mozilla.com> (Original Author)
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
<!DOCTYPE overlay [
|
||||
<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
|
||||
%placesDTD;
|
||||
]>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/editBookmarkOverlay.css"?>
|
||||
|
||||
<overlay id="editBookmarkOverlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/editBookmarkOverlay.js"/>
|
||||
|
||||
<vbox id="editBookmarkPanelContent">
|
||||
<grid id="editBookmarkPanelGrid" flex="1">
|
||||
<columns>
|
||||
<column/>
|
||||
<column flex="1"/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row align="center" id="editBMPanel_nameRow">
|
||||
<label value="&editBookmarkOverlay.name.label;"
|
||||
contorl="editBMPanel_namePicker"/>
|
||||
<menulist id="editBMPanel_namePicker"
|
||||
flex="1"
|
||||
editable="true"
|
||||
droppable="false"
|
||||
oninput="gAddBookmarksPanel.onNamePickerInput();">
|
||||
<menupopup>
|
||||
<menuitem id="editBMPanel_userEnteredName"/>
|
||||
<menuitem disabled="true">
|
||||
<menuseparator flex="1"/>
|
||||
<label value="&editBookmarkOverlay.liveTitlesSeparator.label;"/>
|
||||
</menuitem>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</row>
|
||||
<row align="center" id="editBMPanel_folderRow">
|
||||
<label value="&editBookmarkOverlay.folder.label;"
|
||||
control="editBMPanel_folderMenuList"/>
|
||||
<menulist id="editBMPanel_folderMenuList"
|
||||
class="folder-icon"
|
||||
oncommand="gAddBookmarksPanel.onMenuListFolderSelect();">
|
||||
<menupopup>
|
||||
<!-- Static item for special folders -->
|
||||
<menuitem id="editBMPanel_placesRootItem"
|
||||
label="&editBookmarkOverlay.allBookmarksFolderItem.label;"
|
||||
class="menuitem-iconic folder-icon"/>
|
||||
<menuitem id="editBMPanel_bmRootItem"
|
||||
label="&editBookmarkOverlay.bookmarksMenuFolderItem.label;"
|
||||
class="menuitem-iconic folder-icon"/>
|
||||
<menuitem id="editBMPanel_toolbarFolderItem"
|
||||
label="&editBookmarkOverlay.toolbarFolderItem.label;"
|
||||
class="menuitem-iconic folder-icon"/>
|
||||
<menuseparator id="editBMPanel_foldersSeparator" hidden="true"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<button id="editBMPanel_foldersExpander"
|
||||
class="expander-down"
|
||||
tooltiptext="&editBookmarkOverlay.foldersExpanderDown.tooltip;"
|
||||
tooltiptextdown="&editBookmarkOverlay.foldersExpanderDown.tooltip;"
|
||||
tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
|
||||
oncommand="gAddBookmarksPanel.toggleFolderTreeVisibility();"/>
|
||||
</row>
|
||||
<tree id="editBMPanel_folderTree"
|
||||
class="placesTree"
|
||||
type="places"
|
||||
height="150"
|
||||
collapsed="true"
|
||||
onselect="gAddBookmarksPanel.onFolderTreeSelect();"
|
||||
showRoot="true"
|
||||
place="place:folder=2&group=3&excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1"
|
||||
hidecolumnpicker="true">
|
||||
<treecols>
|
||||
<treecol anonid="title" flex="1" primary="true" hideheader="true"/>
|
||||
</treecols>
|
||||
<treechildren flex="1"/>
|
||||
</tree>
|
||||
<row align="center" id="editBMPanel_tagsRow">
|
||||
<label value="&editBookmarkOverlay.tags.label;"
|
||||
control="tagsField"/>
|
||||
<textbox id="editBMPanel_tagsField"/>
|
||||
<button id="editBMPanel_tagsSelectorExpander"
|
||||
class="expander-down"
|
||||
tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
|
||||
tooltiptextdown="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
|
||||
tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
|
||||
oncommand="gAddBookmarksPanel.toggleTagsSelector();"/>
|
||||
</row>
|
||||
|
||||
<!-- XXX: Temporary workaround -->
|
||||
</rows></grid>
|
||||
<listbox id="editBMPanel_tagsSelector" height="150" collapsed="true"/>
|
||||
<grid flex="1"><columns><column/><column flex="1"/></columns><rows>
|
||||
|
||||
<row id="editBMPanel_descriptionRow" align="center">
|
||||
<label value="&editBookmarkOverlay.description.label;"
|
||||
control="editBMPanel_descriptionField"/>
|
||||
<textbox id="editBMPanel_descriptionField"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
|
||||
<hbox>
|
||||
<spacer flex="1"/>
|
||||
<button label="&editBookmarkOverlay.delete.label;"
|
||||
oncommand="gAddBookmarksPanel.deleteAndClose();"/>
|
||||
<button label="&editBookmarkOverlay.ok.label;"
|
||||
default="true"
|
||||
oncommand="gAddBookmarksPanel.accept();"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</overlay>
|
|
@ -427,7 +427,8 @@ PlacesTreeView.prototype = {
|
|||
COLUMN_TYPE_LASTMODIFIED: 8,
|
||||
|
||||
_getColumnType: function PTV__getColumnType(aColumn) {
|
||||
switch (aColumn.id) {
|
||||
var columnType = aColumn.id || aColumn.element.getAttribute("anonid");
|
||||
switch (columnType) {
|
||||
case "title":
|
||||
return this.COLUMN_TYPE_TITLE;
|
||||
case "url":
|
||||
|
@ -876,7 +877,8 @@ PlacesTreeView.prototype = {
|
|||
},
|
||||
|
||||
getCellProperties: function PTV_getCellProperties(aRow, aColumn, aProperties) {
|
||||
if (aColumn.id != "title")
|
||||
var columnType = aColumn.id || aColumn.element.getAttribute("anonid") ;
|
||||
if (columnType != "title")
|
||||
return;
|
||||
|
||||
this._ensureValidRow(aRow);
|
||||
|
|
|
@ -159,6 +159,16 @@ var PlacesUtils = {
|
|||
return this._microsummaries;
|
||||
},
|
||||
|
||||
/**
|
||||
* The Places Tagging Service
|
||||
*/
|
||||
get tagging() {
|
||||
if (!this._tagging)
|
||||
this._tagging = Cc["@mozilla.org/browser/tagging-service;1"].
|
||||
getService(Ci.nsITaggingService);
|
||||
return this._tagging;
|
||||
},
|
||||
|
||||
_RDF: null,
|
||||
get RDF() {
|
||||
if (!this._RDF)
|
||||
|
@ -1349,15 +1359,16 @@ var PlacesUtils = {
|
|||
setAnnotationsForURI: function PU_setAnnotationsForURI(aURI, aAnnos) {
|
||||
var annosvc = this.annotations;
|
||||
aAnnos.forEach(function(anno) {
|
||||
var flags = ("flags" in anno) ? anno.flags : 0;
|
||||
var expires = ("expires" in anno) ?
|
||||
anno.expires : Ci.nsIAnnotationService.EXPIRE_NEVER;
|
||||
if (anno.type == annosvc.TYPE_BINARY) {
|
||||
annosvc.setPageAnnotationBinary(aURI, anno.name, anno.value,
|
||||
anno.value.length, anno.mimeType,
|
||||
anno.flags, anno.expires);
|
||||
}
|
||||
else {
|
||||
annosvc.setPageAnnotation(aURI, anno.name, anno.value,
|
||||
anno.flags, anno.expires);
|
||||
flags, expires);
|
||||
}
|
||||
else
|
||||
annosvc.setPageAnnotation(aURI, anno.name, anno.value, flags, expires);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1373,14 +1384,17 @@ var PlacesUtils = {
|
|||
setAnnotationsForItem: function PU_setAnnotationsForItem(aItemId, aAnnos) {
|
||||
var annosvc = this.annotations;
|
||||
aAnnos.forEach(function(anno) {
|
||||
var flags = ("flags" in anno) ? anno.flags : 0;
|
||||
var expires = ("expires" in anno) ?
|
||||
anno.expires : Ci.nsIAnnotationService.EXPIRE_NEVER;
|
||||
if (anno.type == annosvc.TYPE_BINARY) {
|
||||
annosvc.setItemAnnotationBinary(aItemId, anno.name, anno.value,
|
||||
anno.value.length, anno.mimeType,
|
||||
anno.flags, anno.expires);
|
||||
flags, expires);
|
||||
}
|
||||
else {
|
||||
annosvc.setItemAnnotation(aItemId, anno.name, anno.value,
|
||||
anno.flags, anno.expires);
|
||||
annosvc.setItemAnnotation(aItemId, anno.name, anno.value, flags,
|
||||
expires);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -1439,6 +1453,13 @@ var PlacesUtils = {
|
|||
return this._toolbarFolderId;
|
||||
},
|
||||
|
||||
get tagRootId() {
|
||||
if (!("_tagRootId" in this))
|
||||
this._tagRootId = this.bookmarks.tagRoot;
|
||||
|
||||
return this._tagRootId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the POST data associated with a URI, if any.
|
||||
* Used by POST keywords.
|
||||
|
@ -1466,6 +1487,19 @@ var PlacesUtils = {
|
|||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the description of an item
|
||||
* @param aItemId
|
||||
* item identifier
|
||||
* @returns the description of the given item, or an empty string if it is
|
||||
* not set.
|
||||
*/
|
||||
getItemDescription: function PU_getItemDescription(aItemId) {
|
||||
if (this.annotations.itemHasAnnotation(aItemId, DESCRIPTION_ANNO))
|
||||
return this.annotations.getItemAnnotation(aItemId, DESCRIPTION_ANNO);
|
||||
return "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts a JavaScript object into a JSON string
|
||||
* (see http://www.json.org/ for the full grammar).
|
||||
|
|
|
@ -31,3 +31,5 @@ browser.jar:
|
|||
* content/browser/bookmarks/sidebarUtils.js (content/sidebarUtils.js)
|
||||
* content/browser/places/moveBookmarks.xul (content/moveBookmarks.xul)
|
||||
* content/browser/places/moveBookmarks.js (content/moveBookmarks.js)
|
||||
* content/browser/places/editBookmarkOverlay.xul (content/editBookmarkOverlay.xul)
|
||||
* content/browser/places/editBookmarkOverlay.js (content/editBookmarkOverlay.js)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!ENTITY editBookmarkOverlay.name.label "Name:">
|
||||
<!ENTITY editBookmarkOverlay.liveTitlesSeparator.label "Live Titles">
|
||||
<!ENTITY editBookmarkOverlay.folder.label "Folder:">
|
||||
<!ENTITY editBookmarkOverlay.allBookmarksFolderItem.label "All Bookmarks">
|
||||
<!ENTITY editBookmarkOverlay.bookmarksMenuFolderItem.label "Bookmarks Menu">
|
||||
<!ENTITY editBookmarkOverlay.toolbarFolderItem.label "Bookmarks Toolbar">
|
||||
<!ENTITY editBookmarkOverlay.foldersExpanderDown.tooltip "Show all the bookmarks folders">
|
||||
<!ENTITY editBookmarkOverlay.expanderUp.tooltip "Hide">
|
||||
<!ENTITY editBookmarkOverlay.tags.label "Tags">
|
||||
<!ENTITY editBookmarkOverlay.description.label "Description:">
|
||||
<!ENTITY editBookmarkOverlay.tagsExpanderDown.tooltip "Show all tags">
|
||||
<!ENTITY editBookmarkOverlay.ok.label "OK">
|
||||
<!ENTITY editBookmarkOverlay.delete.label "Delete">
|
|
@ -27,6 +27,7 @@
|
|||
locale/browser/sessionstore.properties (%chrome/browser/sessionstore.properties)
|
||||
locale/browser/places/places.dtd (%chrome/browser/places/places.dtd)
|
||||
locale/browser/places/places.properties (%chrome/browser/places/places.properties)
|
||||
locale/browser/places/editBookmarkOverlay.dtd (%chrome/browser/places/editBookmarkOverlay.dtd)
|
||||
locale/browser/places/bookmarkProperties.dtd (%chrome/browser/places/bookmarkProperties.dtd)
|
||||
locale/browser/places/bookmarkProperties.properties (%chrome/browser/places/bookmarkProperties.properties)
|
||||
locale/browser/preferences/selectBookmark.dtd (%chrome/browser/preferences/selectBookmark.dtd)
|
||||
|
|
|
@ -1269,3 +1269,12 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
|||
-moz-border-bottom-colors: -moz-mac-menushadow -moz-mac-menushadow ThreeDShadow !important;
|
||||
-moz-border-left-colors: ThreeDLightShadow ThreeDHighlight !important;
|
||||
}
|
||||
|
||||
/* star icon */
|
||||
#star-icon {
|
||||
list-style-image: url("chrome://browser/skin/places/starPage.png");
|
||||
}
|
||||
|
||||
#star-icon[starred="true"] {
|
||||
list-style-image: url("chrome://browser/skin/places/pageStarred.png");
|
||||
}
|
||||
|
|
|
@ -44,6 +44,9 @@ classic.jar:
|
|||
skin/classic/browser/places/livemarkFolder.png (places/livemarkFolder.png)
|
||||
skin/classic/browser/places/livemarkFolderHover.png (places/livemarkFolderHover.png)
|
||||
skin/classic/browser/places/bookmarkProperties.css (places/bookmarkProperties.css)
|
||||
skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
|
||||
skin/classic/browser/places/starPage.png (places/starPage.png)
|
||||
skin/classic/browser/places/pageStarred.png (places/pageStarred.png)
|
||||
skin/classic/browser/places/organizer-toolbar.png (bookmarks/Bookmarks-toolbar.png)
|
||||
skin/classic/browser/places/expander-closed-active.png (bookmarks/expander-closed-active.png)
|
||||
skin/classic/browser/places/expander-closed.png (bookmarks/expander-closed.png)
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Firefox.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Myk Melez <myk@mozilla.org>
|
||||
* Asaf Romano <mano@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||
|
||||
/**** folder menulist ****/
|
||||
.folder-icon > .menulist-label-box > .menulist-icon,
|
||||
.folder-icon > .menu-iconic-left > .menu-iconic-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.folder-icon > .menu-iconic-left {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
.folder-icon {
|
||||
list-style-image: url("chrome://global/skin/tree/folder.png") !important;
|
||||
}
|
||||
|
||||
.menulist-icon {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/**** folder tree ****/
|
||||
|
||||
#editBMPanel_folderTree {
|
||||
margin: 6px 0;
|
||||
}
|
||||
|
||||
/**** expanders ****/
|
||||
|
||||
.expander-up,
|
||||
.expander-down {
|
||||
-moz-appearance: none;
|
||||
margin-left: 8px;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.expander-up {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-open.png") !important;
|
||||
}
|
||||
|
||||
.expander-down {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-closed.png") !important;
|
||||
}
|
||||
|
||||
.expander-down:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-closed-active.png") !important;
|
||||
}
|
||||
|
||||
.expander-up:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-open-active.png") !important;
|
||||
}
|
||||
|
||||
/**** name picker ****/
|
||||
|
||||
/* Make the microsummary picker look like a regular textbox instead of
|
||||
* an editable menulist when no microsummaries are available.
|
||||
*/
|
||||
#editBMPanel_namePicker[droppable="false"] {
|
||||
-moz-appearance: none;
|
||||
margin: 0px;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#editBMPanel_namePicker[droppable="false"] > .menulist-editable-box {
|
||||
/* These rules are duplicates of the rules for the textbox element
|
||||
* in textbox.css and should track changes in that file.
|
||||
*/
|
||||
-moz-appearance: textfield;
|
||||
cursor: text;
|
||||
margin: 2px 4px;
|
||||
border: 2px solid;
|
||||
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
|
||||
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
|
||||
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
|
||||
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
|
||||
padding: 2px 2px 3px 4px;
|
||||
background-color: -moz-Field;
|
||||
color: -moz-FieldText;
|
||||
}
|
||||
|
||||
#editBMPanel_namePicker[droppable="false"] > .menulist-editable-box > html|*.textbox-input {
|
||||
margin: 0px !important;
|
||||
border: none !important;
|
||||
padding: 0px !important;
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
/* Hide the drop marker and the popup. */
|
||||
|
||||
#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#editBMPanel_namePicker[droppable="false"] > menupopup {
|
||||
display: none;
|
||||
}
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.2 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.0 KiB |
|
@ -1439,3 +1439,12 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
|||
.bookmark-item[dragover-bottom="true"] {
|
||||
-moz-border-bottom-colors: #000000;
|
||||
}
|
||||
|
||||
/* star icon */
|
||||
#star-icon {
|
||||
list-style-image: url("chrome://browser/skin/places/starPage.png");
|
||||
}
|
||||
|
||||
#star-icon[starred="true"] {
|
||||
list-style-image: url("chrome://browser/skin/places/pageStarred.png");
|
||||
}
|
||||
|
|
|
@ -50,6 +50,9 @@ classic.jar:
|
|||
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
||||
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
||||
skin/classic/browser/places/folderDragOver.png (places/folderDragOver.png)
|
||||
skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
|
||||
skin/classic/browser/places/starPage.png (places/starPage.png)
|
||||
skin/classic/browser/places/pageStarred.png (places/pageStarred.png)
|
||||
skin/classic/browser/places/bookmarkProperties.css (places/bookmarkProperties.css)
|
||||
skin/classic/browser/places/organizer-toolbar.png (bookmarks/Bookmarks-toolbar.png)
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Firefox.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Myk Melez <myk@mozilla.org>
|
||||
* Asaf Romano <mano@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**** folder menulist ****/
|
||||
.folder-icon > .menulist-label-box > .menulist-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.folder-icon > .menu-iconic-left {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
.folder-icon {
|
||||
list-style-image: url("chrome://global/skin/icons/folder-item.png") !important;
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px) !important;
|
||||
}
|
||||
|
||||
|
||||
/**** expanders ****/
|
||||
|
||||
.expander-up,
|
||||
.expander-down {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.expander-up {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
|
||||
}
|
||||
|
||||
.expander-down {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif");
|
||||
}
|
||||
|
||||
.expander-down:hover:active {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-dn-hov.gif");
|
||||
}
|
||||
|
||||
.expander-up:hover:active {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-up-hov.gif");
|
||||
}
|
||||
|
||||
/**** name picker ****/
|
||||
|
||||
/* Make the microsummary picker look like a regular textbox instead of
|
||||
* an editable menulist when no microsummaries are available.
|
||||
*/
|
||||
#editBMPanel_namePicker[droppable="false"] {
|
||||
/* These rules come from the textbox element in textbox.css. */
|
||||
|
||||
/* Normal editable menulists set this to "none". */
|
||||
-moz-appearance: textfield;
|
||||
cursor: text;
|
||||
|
||||
border: 2px solid;
|
||||
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
|
||||
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
|
||||
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
|
||||
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
|
||||
background-color: -moz-Field;
|
||||
color: -moz-FieldText;
|
||||
}
|
||||
|
||||
#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker {
|
||||
/* Normal editable menulists set this to "menulist-textfield". */
|
||||
-moz-appearance: none;
|
||||
padding: 2px 2px 3px 4px;
|
||||
}
|
||||
|
||||
|
||||
/* Hide the drop marker and the popup. */
|
||||
|
||||
#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker,
|
||||
#editBMPanel_namePicker[droppable="false"] > menupopup {
|
||||
display: none;
|
||||
}
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.2 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.0 KiB |
|
@ -15,12 +15,12 @@
|
|||
* The Original Code is Places Tagging Service code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Asaf Romano <mano@mozilla.com>
|
||||
* Asaf Romano <mano@mozilla.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -41,7 +41,7 @@
|
|||
interface nsIURI;
|
||||
interface nsIVariant;
|
||||
|
||||
[scriptable, uuid(962bf94f-e719-4cf6-8967-74ff5d2020df)]
|
||||
[scriptable, uuid(03dd79c2-c834-4747-a204-79d5a29c6bd9)]
|
||||
interface nsITaggingService : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -54,9 +54,7 @@ interface nsITaggingService : nsISupports
|
|||
* @param aTags
|
||||
* Array of tags to set for the given URL.
|
||||
*/
|
||||
void tagURI(in nsIURI aURI,
|
||||
[const, array, size_is(aCount)] in wstring aTags,
|
||||
in unsigned long aCount);
|
||||
void tagURI(in nsIURI aURI, in nsIVariant aTags);
|
||||
|
||||
/**
|
||||
* Removes tags from a URL. Tags from aTags which are not set for the
|
||||
|
@ -65,11 +63,10 @@ interface nsITaggingService : nsISupports
|
|||
* @param aURI
|
||||
* the URL to un-tag.
|
||||
* @param aTags
|
||||
* Array of tags to unset.
|
||||
* Array of tags to unset. pass null to remove all tags from the given
|
||||
* url.
|
||||
*/
|
||||
void untagURI(in nsIURI aURI,
|
||||
[const, array, size_is(aCount)] in wstring aTags,
|
||||
in unsigned long aCount);
|
||||
void untagURI(in nsIURI aURI, in nsIVariant aTags);
|
||||
|
||||
/**
|
||||
* Retrieves all URLs tagged with the given tag.
|
||||
|
@ -88,4 +85,9 @@ interface nsITaggingService : nsISupports
|
|||
* @returns array of tags (sorted by name).
|
||||
*/
|
||||
nsIVariant getTagsForURI(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Retrieves all tags used to tag URIs in the data-base (sorted by name).
|
||||
*/
|
||||
readonly attribute nsIVariant allTags;
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* The Original Code is the Places Tagging Service
|
||||
* The Original Code is the Places Tagging Service.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
|
@ -20,7 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Asaf Romano <mano@mozilla.com>
|
||||
* Asaf Romano <mano@mozilla.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -40,16 +40,16 @@ const Cc = Components.classes;
|
|||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
const TAGS_CLASSID = Components.ID("{6a059068-1630-11dc-8314-0800200c9a66}");
|
||||
const TAGS_CLASSNAME = "Places Tagging Service";
|
||||
const TAGS_CONTRACTID = "@mozilla.org/browser/tagging-service;1";
|
||||
|
||||
const TAG_CONTAINER_ICON_URI = "chrome://mozapps/skin/places/tagContainerIcon.png"
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const NH_CONTRACTID = "@mozilla.org/browser/nav-history-service;1";
|
||||
const BMS_CONTRACTID = "@mozilla.org/browser/nav-bookmarks-service;1";
|
||||
const IO_CONTRACTID = "@mozilla.org/network/io-service;1";
|
||||
const ANNO_CONTRACTID = "@mozilla.org/browser/annotation-service;1";
|
||||
const FAV_CONTRACTID = "@mozilla.org/browser/favicon-service;1";
|
||||
const OBSS_CONTRACTID = "@mozilla.org/observer-service;1";
|
||||
|
||||
const TAG_CONTAINER_ICON_URI = "chrome://mozapps/skin/places/tagContainerIcon.png"
|
||||
|
||||
var gIoService = Cc[IO_CONTRACTID].getService(Ci.nsIIOService);
|
||||
|
||||
|
@ -57,20 +57,6 @@ var gIoService = Cc[IO_CONTRACTID].getService(Ci.nsIIOService);
|
|||
* The Places Tagging Service
|
||||
*/
|
||||
function TaggingService() {
|
||||
this._tags = [];
|
||||
|
||||
var options = this._history.getNewQueryOptions();
|
||||
var query = this._history.getNewQuery();
|
||||
query.setFolders([this._bms.tagRoot], 1);
|
||||
var result = this._history.executeQuery(query, options);
|
||||
var rootNode = result.root;
|
||||
rootNode.containerOpen = true;
|
||||
|
||||
var cc = rootNode.childCount;
|
||||
for (var i=0; i < cc; i++) {
|
||||
var child = rootNode.getChild(i);
|
||||
this._tags.push({ itemId: child.itemId, name: child.title });
|
||||
}
|
||||
}
|
||||
|
||||
TaggingService.prototype = {
|
||||
|
@ -86,24 +72,49 @@ TaggingService.prototype = {
|
|||
return this.__history;
|
||||
},
|
||||
|
||||
// nsISupports
|
||||
QueryInterface: function TS_QueryInterface(iid) {
|
||||
if (iid.equals(Ci.nsITaggingService) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NO_INTERFACE;
|
||||
get _annos() {
|
||||
if (!this.__annos)
|
||||
this.__annos = Cc[ANNO_CONTRACTID].getService(Ci.nsIAnnotationService);
|
||||
return this.__annos;
|
||||
},
|
||||
|
||||
get _tagsResult() {
|
||||
if (!this.__tagsResult) {
|
||||
var options = this._history.getNewQueryOptions();
|
||||
var query = this._history.getNewQuery();
|
||||
query.setFolders([this._bms.tagRoot], 1);
|
||||
this.__tagsResult = this._history.executeQuery(query, options);
|
||||
this.__tagsResult.root.containerOpen = true;
|
||||
|
||||
// we need to null out the result on shutdown
|
||||
var observerSvc = Cc[OBSS_CONTRACTID].getService(Ci.nsIObserverService);
|
||||
observerSvc.addObserver(this, "xpcom-shutdown", false);
|
||||
}
|
||||
return this.__tagsResult;
|
||||
},
|
||||
|
||||
// Feed XPCOMUtils
|
||||
classDescription: "Places Tagging Service",
|
||||
contractID: "@mozilla.org/browser/tagging-service;1",
|
||||
classID: Components.ID("{6a059068-1630-11dc-8314-0800200c9a66}"),
|
||||
|
||||
// nsISupports
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsITaggingService,
|
||||
Ci.nsIObserver]),
|
||||
|
||||
/**
|
||||
* If there's no tag with the given name, -1 is returned.
|
||||
* If there's no tag with the given name, null is returned;
|
||||
*/
|
||||
_getTagIndex: function TS__getTagIndex(aName) {
|
||||
for (var i=0; i < this._tags.length; i++) {
|
||||
if (this._tags[i].name == aName)
|
||||
return i;
|
||||
_getTagNode: function TS__getTagIndex(aName) {
|
||||
var root = this._tagsResult.root;
|
||||
var cc = root.childCount;
|
||||
for (var i=0; i < cc; i++) {
|
||||
var child = root.getChild(i);
|
||||
if (child.title == aName)
|
||||
return child;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return null;
|
||||
},
|
||||
|
||||
get _tagContainerIcon() {
|
||||
|
@ -116,7 +127,7 @@ TaggingService.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Creates a tag container under the tags-root with the given name
|
||||
* Creates a tag container under the tags-root with the given name.
|
||||
*
|
||||
* @param aName
|
||||
* the name for the new container.
|
||||
|
@ -125,7 +136,6 @@ TaggingService.prototype = {
|
|||
_createTag: function TS__createTag(aName) {
|
||||
var id = this._bms.createFolder(this._bms.tagRoot, aName,
|
||||
this._bms.DEFAULT_INDEX);
|
||||
this._tags.push({ itemId: id, name: aName});
|
||||
|
||||
// Set the favicon
|
||||
var faviconService = Cc[FAV_CONTRACTID].getService(Ci.nsIFaviconService);
|
||||
|
@ -164,22 +174,22 @@ TaggingService.prototype = {
|
|||
},
|
||||
|
||||
// nsITaggingService
|
||||
tagURI: function TS_tagURI(aURI, aTags, aCount) {
|
||||
if (!aURI)
|
||||
tagURI: function TS_tagURI(aURI, aTags) {
|
||||
if (!aURI || !aTags)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
|
||||
for (var i=0; i < aTags.length; i++) {
|
||||
if (aTags[i].length == 0)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
|
||||
var tagIndex = this._getTagIndex(aTags[i]);
|
||||
if (tagIndex == -1) {
|
||||
var tagNode = this._getTagNode(aTags[i]);
|
||||
if (!tagNode) {
|
||||
var tagId = this._createTag(aTags[i]);
|
||||
this._bms.insertBookmark(tagId, aURI, this._bms.DEFAULT_INDEX, "");
|
||||
}
|
||||
else {
|
||||
var tagId = this._tags[tagIndex].itemId;
|
||||
if (!this._isURITaggedInternal(aURI, tagId, {}))
|
||||
var tagId = tagNode.itemId;
|
||||
if (!this._isURITaggedInternal(aURI, tagNode.itemId, {}))
|
||||
this._bms.insertBookmark(tagId, aURI, this._bms.DEFAULT_INDEX, "");
|
||||
}
|
||||
}
|
||||
|
@ -188,38 +198,41 @@ TaggingService.prototype = {
|
|||
/**
|
||||
* Removes the tag container from the tags-root if the given tag is empty.
|
||||
*
|
||||
* @param aTagIndex
|
||||
* the index of a tag element under the _tags array
|
||||
* @param aTagId
|
||||
* the item-id of the tag element under the tags root
|
||||
*/
|
||||
_removeTagAtIndexIfEmpty: function TS__removeTagAtIndexIfEmpty(aTagIndex) {
|
||||
_removeTagIfEmpty: function TS__removeTagIfEmpty(aTagId) {
|
||||
var options = this._history.getNewQueryOptions();
|
||||
var query = this._history.getNewQuery();
|
||||
query.setFolders([this._tags[aTagIndex].itemId], 1);
|
||||
query.setFolders([aTagId], 1);
|
||||
var result = this._history.executeQuery(query, options);
|
||||
var rootNode = result.root;
|
||||
rootNode.containerOpen = true;
|
||||
if (rootNode.childCount == 0) {
|
||||
this._bms.removeFolder(this._tags[aTagIndex].itemId);
|
||||
this._tags.splice(aTagIndex, 1);
|
||||
}
|
||||
if (rootNode.childCount == 0)
|
||||
this._bms.removeFolder(aTagId);
|
||||
},
|
||||
|
||||
// nsITaggingService
|
||||
untagURI: function TS_untagURI(aURI, aTags, aCount) {
|
||||
untagURI: function TS_untagURI(aURI, aTags) {
|
||||
if (!aURI)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
|
||||
if (!aTags) {
|
||||
// see IDL.
|
||||
// XXXmano: write a perf-sensitive version of this code path...
|
||||
aTags = this.getTagsForURI(aURI);
|
||||
}
|
||||
|
||||
for (var i=0; i < aTags.length; i++) {
|
||||
if (aTags[i].length == 0)
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
|
||||
var tagIndex = this._getTagIndex(aTags[i]);
|
||||
if (tagIndex != -1) {
|
||||
var tagNode = this._getTagNode(aTags[i]);
|
||||
if (tagNode) {
|
||||
var itemId = { };
|
||||
if (this._isURITaggedInternal(aURI, this._tags[tagIndex].itemId,
|
||||
itemId)) {
|
||||
if (this._isURITaggedInternal(aURI, tagNode.itemId, itemId)) {
|
||||
this._bms.removeItem(itemId.value);
|
||||
this._removeTagAtIndexIfEmpty(tagIndex);
|
||||
this._removeTagIfEmpty(tagNode.itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,18 +244,14 @@ TaggingService.prototype = {
|
|||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
|
||||
var uris = [];
|
||||
var tagIndex = this._getTagIndex(aTag);
|
||||
if (tagIndex != -1) {
|
||||
var tagId = this._tags[tagIndex].itemId;
|
||||
var options = this._history.getNewQueryOptions();
|
||||
var query = this._history.getNewQuery();
|
||||
query.setFolders([tagId], 1);
|
||||
var result = this._history.executeQuery(query, options);
|
||||
var rootNode = result.root;
|
||||
rootNode.containerOpen = true;
|
||||
var cc = rootNode.childCount;
|
||||
var tagNode = this._getTagNode(aTag);
|
||||
if (tagNode) {
|
||||
tagNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
|
||||
tagNode.containerOpen = true;
|
||||
var cc = tagNode.childCount;
|
||||
for (var i=0; i < cc; i++)
|
||||
uris.push(gIoService.newURI(rootNode.getChild(i).uri, null, null));
|
||||
uris.push(gIoService.newURI(tagNode.getChild(i).uri, null, null));
|
||||
tagNode.containerOpen = false;
|
||||
}
|
||||
return uris;
|
||||
},
|
||||
|
@ -253,72 +262,49 @@ TaggingService.prototype = {
|
|||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
|
||||
var tags = [];
|
||||
|
||||
var bookmarkIds = this._bms.getBookmarkIdsForURI(aURI, {});
|
||||
var root = this._tagsResult.root;
|
||||
var cc = root.childCount;
|
||||
for (var i=0; i < bookmarkIds.length; i++) {
|
||||
var parent = this._bms.getFolderIdForItem(bookmarkIds[i]);
|
||||
for (var j=0; j < this._tags.length; j++) {
|
||||
if (this._tags[j].itemId == parent)
|
||||
tags.push(this._tags[j].name);
|
||||
for (var j=0; j < cc; j++) {
|
||||
var child = root.getChild(j);
|
||||
if (child.itemId == parent)
|
||||
tags.push(child.title);
|
||||
}
|
||||
}
|
||||
|
||||
// sort the tag list
|
||||
tags.sort();
|
||||
return tags;
|
||||
}
|
||||
};
|
||||
|
||||
var gModule = {
|
||||
registerSelf: function(componentManager, fileSpec, location, type) {
|
||||
componentManager = componentManager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
|
||||
for (var key in this._objects) {
|
||||
var obj = this._objects[key];
|
||||
componentManager.registerFactoryLocation(obj.CID,
|
||||
obj.className,
|
||||
obj.contractID,
|
||||
fileSpec,
|
||||
location,
|
||||
type);
|
||||
}
|
||||
},
|
||||
|
||||
unregisterSelf: function(componentManager, fileSpec, location) {},
|
||||
|
||||
getClassObject: function(componentManager, cid, iid) {
|
||||
if (!iid.equals(Components.interfaces.nsIFactory))
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
for (var key in this._objects) {
|
||||
if (cid.equals(this._objects[key].CID))
|
||||
return this._objects[key].factory;
|
||||
}
|
||||
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
_objects: {
|
||||
service: {
|
||||
CID : TAGS_CLASSID,
|
||||
contractID : TAGS_CONTRACTID,
|
||||
className : TAGS_CLASSNAME,
|
||||
factory : TaggingServiceFactory = {
|
||||
createInstance: function(aOuter, aIID) {
|
||||
if (aOuter != null)
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
var svc = new TaggingService();
|
||||
return svc.QueryInterface(aIID);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
canUnload: function(componentManager) {
|
||||
return true;
|
||||
// nsITaggingService
|
||||
get allTags() {
|
||||
var tags = [];
|
||||
var root = this._tagsResult.root;
|
||||
var cc = root.childCount;
|
||||
for (var j=0; j < cc; j++) {
|
||||
var child = root.getChild(j);
|
||||
tags.push(child.title);
|
||||
}
|
||||
|
||||
// sort the tag list
|
||||
tags.sort();
|
||||
return tags;
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
observe: function TS_observe(subject, topic, data) {
|
||||
if (topic == "xpcom-shutdown") {
|
||||
this.__tagsResult.root.containerOpen = false;
|
||||
this.__tagsResult = null;
|
||||
var observerSvc = Cc[OBSS_CONTRACTID].getService(Ci.nsIObserverService);
|
||||
observerSvc.removeObserver(this, "xpcom-shutdown");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function NSGetModule(compMgr, fileSpec) {
|
||||
return gModule;
|
||||
return XPCOMUtils.generateModule([TaggingService]);
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
* The Original Code is Places Tagging Service unit test code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Asaf Romano <mano@mozilla.com>
|
||||
* Asaf Romano <mano@mozilla.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -78,8 +78,8 @@ function run_test() {
|
|||
var uri2 = uri("https://bar.tld/");
|
||||
|
||||
// this also tests that the multiple folders are not created for the same tag
|
||||
tagssvc.tagURI(uri1, ["tag 1"], 1);
|
||||
tagssvc.tagURI(uri2, ["tag 1"], 1);
|
||||
tagssvc.tagURI(uri1, ["tag 1"]);
|
||||
tagssvc.tagURI(uri2, ["tag 1"]);
|
||||
do_check_eq(tagRoot.childCount, 1);
|
||||
|
||||
var tag1node = tagRoot.getChild(0)
|
||||
|
@ -89,12 +89,12 @@ function run_test() {
|
|||
do_check_eq(tag1node.childCount, 2);
|
||||
|
||||
// Tagging the same url twice with the same tag should be a no-op
|
||||
tagssvc.tagURI(uri1, ["tag 1"], 1);
|
||||
tagssvc.tagURI(uri1, ["tag 1"]);
|
||||
do_check_eq(tag1node.childCount, 2);
|
||||
|
||||
// the former should be ignored.
|
||||
do_check_eq(tagRoot.childCount, 1);
|
||||
tagssvc.tagURI(uri1, ["tag 1", "tag 2"], 2);
|
||||
tagssvc.tagURI(uri1, ["tag 1", "tag 2"]);
|
||||
do_check_eq(tagRoot.childCount, 2);
|
||||
|
||||
// test getTagsForURI
|
||||
|
@ -112,10 +112,16 @@ function run_test() {
|
|||
do_check_true(tag1uris[0].equals(uri1));
|
||||
do_check_true(tag1uris[1].equals(uri2));
|
||||
|
||||
tagssvc.untagURI(uri1, ["tag 1"], 1);
|
||||
// test allTags attribute
|
||||
var allTags = tagssvc.allTags;
|
||||
do_check_eq(allTags.length, 2);
|
||||
do_check_eq(allTags[0], "tag 1");
|
||||
do_check_eq(allTags[1], "tag 2");
|
||||
|
||||
tagssvc.untagURI(uri1, ["tag 1"]);
|
||||
do_check_eq(tag1node.childCount, 1);
|
||||
|
||||
// removing the last uri from a tag should remove the tag-container
|
||||
tagssvc.untagURI(uri2, ["tag 1"], 1);
|
||||
tagssvc.untagURI(uri2, ["tag 1"]);
|
||||
do_check_eq(tagRoot.childCount, 1);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче