mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-29 21:25:35 +00:00
c5056a6b59
bug=339481 r=mconnor
307 lines
11 KiB
JavaScript
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");
|
|
}
|