gecko-dev/browser/components/bookmarks/content/microsummaryPicker.js
2006-08-02 02:05:09 +00:00

307 lines
11 KiB
JavaScript

//* -*- 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 Microsummarizer.
*
* 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>
*
* 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 ***** */
// XXX Synchronize these values with the VARIANT constants in Places code?
const ADD_BOOKMARK_MODE = 0;
const EDIT_BOOKMARK_MODE = 1;
const Cc = Components.classes;
const Ci = Components.interfaces;
var MicrosummaryPicker = {
// The microsummary service.
__mss: null,
get _mss() {
if (!this.__mss)
this.__mss = Cc["@mozilla.org/microsummary/service;1"].
getService(Ci.nsIMicrosummaryService);
return this.__mss;
},
// The IO service.
__ios: null,
get _ios() {
if (!this.__ios)
this.__ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
return this.__ios;
},
// The URI of the page being bookmarked.
get _pageURI() {
if (this._mode == ADD_BOOKMARK_MODE)
return this._ios.newURI(gArg.url, null, null);
else if (this._mode == EDIT_BOOKMARK_MODE) {
var uriResource = BMDS.GetTarget(gResource, gProperties[1], true);
if (!uriResource)
return null;
// The URI spec will be the empty string if the user opened the bookmark
// properties dialog via the "New Bookmark" command.
var uriSpec = uriResource.QueryInterface(Ci.nsIRDFLiteral).Value;
if (!uriSpec)
return null;
// The IO Service will throw an exception if it can't convert the spec
// into an nsIURI object.
var uri;
try {
uri = this._ios.newURI(uriSpec, null, null);
}
catch(e) {
return null;
}
return uri;
}
return null;
},
// The unique identifier for the bookmark. If we're adding a bookmark,
// this may not exist yet.
get _bookmarkID() {
if (this._mode == ADD_BOOKMARK_MODE && typeof gResource == "undefined")
return null;
return gResource;
},
_microsummaries: null,
get _mode() {
if ("gArg" in window)
return ADD_BOOKMARK_MODE;
else if ("gProperties" in window)
return EDIT_BOOKMARK_MODE;
return null;
},
/*
* Whether or not the microsummary picker is enabled for this bookmark.
* The picker is enabled for regular pages. It's disabled for livemarks,
* separators, folders, or when bookmarking multiple tabs.
*
* @returns boolean true if the picker is enabled; false otherwise
*
*/
get enabled() {
if (this._mode == ADD_BOOKMARK_MODE) {
// If we're adding a bookmark, we only have to worry about livemarks
// and bookmarking multiple tabs.
if ("feedURL" in gArg || gArg.bBookmarkAllTabs)
return false;
}
else if (this._mode == EDIT_BOOKMARK_MODE) {
// If we're modifying a bookmark, it could be a livemark, separator,
// folder, or regular page. The picker is only enabled for regular pages.
var isLivemark = BookmarksUtils.resolveType(gResource) == "Livemark";
var isSeparator = BookmarksUtils.resolveType(gResource) == "BookmarkSeparator";
var isContainer = RDFCU.IsContainer(BMDS, gResource);
if (isLivemark || isSeparator || isContainer)
return false;
}
else {
// We should never get to this point, since we're only being used
// in the Add Bookmark and Bookmark Properties dialogs, but if we're here
// for some reason, be conservative and assume the picker is disabled.
return false;
}
// We haven't found a reason to disable the picker, so say it's enabled.
return true;
},
init: function MSP_init() {
// Set the label of the menu item representing the user-entered name.
this._updateUserEnteredNameItem();
if (this._pageURI) {
this._microsummaries = this._mss.getMicrosummaries(this._pageURI, this._bookmarkID);
this._microsummaries.addObserver(this._observer);
this.rebuild();
}
},
destroy: function MSP_destroy() {
if (this._pageURI && this._microsummaries)
this._microsummaries.removeObserver(this._observer);
},
rebuild: function MSP_rebuild() {
var microsummaryMenuList = document.getElementById("name");
var microsummaryMenuPopup = document.getElementById("microsummaryMenuPopup");
// Save a reference to the active item (i.e. the item the user is hovering
// over), if any, so we can reactivate it after the rebuild.
var activeMicrosummary;
if (microsummaryMenuList.menuBoxObject.activeChild)
activeMicrosummary = microsummaryMenuList.menuBoxObject.activeChild.microsummary;
// Remove old items from the menu, except for the first item, which holds
// the user-entered name, and the second item, which separates and labels
// the microsummaries below it.
while (microsummaryMenuPopup.childNodes.length > 2)
microsummaryMenuPopup.removeChild(microsummaryMenuPopup.lastChild);
var enumerator = this._microsummaries.Enumerate();
// Show the drop marker if there are microsummaries; otherwise hide it.
// We do this via a microsummary picker-specific "droppable" attribute
// that, when set to "false", activates a "display: none" CSS rule
// on the drop marker.
if (enumerator.hasMoreElements())
microsummaryMenuList.setAttribute("droppable", "true");
else
microsummaryMenuList.setAttribute("droppable", "false");
while (enumerator.hasMoreElements()) {
var microsummary = enumerator.getNext().QueryInterface(Ci.nsIMicrosummary);
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 to the datastore.
menuItem.microsummary = microsummary;
// 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 rebuild the menu.
// 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's in progress.
if (microsummary.content != null)
menuItem.setAttribute("label", microsummary.content);
else {
menuItem.setAttribute("label", microsummary.generator.name ?
microsummary.generator.name : microsummary.generator.uri.spec);
microsummary.update();
}
microsummaryMenuPopup.appendChild(menuItem);
// Select the item if this is the current microsummary for the bookmark.
if (this._bookmarkID && this._mss.isMicrosummary(this._bookmarkID, microsummary))
microsummaryMenuList.selectedItem = menuItem;
// Activate the item if it was active before the rebuild (i.e. the user
// was hovering over it).
if (activeMicrosummary && microsummary == activeMicrosummary)
microsummaryMenuList.menuBoxObject.activeChild = menuItem;
}
},
_observer: {
interfaces: [Ci.nsIMicrosummaryObserver, Ci.nsISupports],
QueryInterface: function (iid) {
//if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
if (!iid.equals(Ci.nsIMicrosummaryObserver) &&
!iid.equals(Ci.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
onContentLoaded: function(microsummary) {
MicrosummaryPicker.rebuild();
},
onElementAppended: function(microsummary) {
MicrosummaryPicker.rebuild();
}
},
/**
* Called when the user types in the microsummary picker's text box.
*
* @param event
* the event object representing the input event
*
*/
onInput: function MSP_onInput(event) {
this._updateUserEnteredNameItem();
},
/**
* Update the menu item representing the user-entered name when the user
* changes the name by typing in the text box.
*
*/
_updateUserEnteredNameItem: function MSP__updateUserEnteredNameItem() {
var nameField = document.getElementById("name");
var nameItem = document.getElementById("userEnteredNameItem");
nameItem.label = nameField.value;
},
commit: function MSP_commit() {
var changed = false;
var menuList = document.getElementById("name");
// Something should always be selected in the microsummary menu,
// but if nothing is selected, then conservatively assume we should
// just display the bookmark title.
if (menuList.selectedIndex == -1)
menuList.selectedIndex = 0;
// This will set microsummary == undefined if the user selected
// the "don't display a microsummary" item.
var newMicrosummary = menuList.selectedItem.microsummary;
if (newMicrosummary == null && this._mss.hasMicrosummary(this._bookmarkID)) {
this._mss.removeMicrosummary(this._bookmarkID);
changed = true;
}
else if (newMicrosummary != null
&& !this._mss.isMicrosummary(this._bookmarkID, newMicrosummary)) {
this._mss.setMicrosummary(this._bookmarkID, newMicrosummary);
changed = true;
}
return changed;
}
};
function debug(str) {
dump(str + "\n");
}