releases-comm-central/mailnews/addrbook/content/abResultsPane.js

508 строки
14 KiB
JavaScript

/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ; js-indent-level: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Use of items in this file require:
*
* getSelectedDirectoryURI()
* returns the URI of the selected directory
* AbResultsPaneDoubleClick(card)
* Is called when the results pane is double-clicked, with the clicked card.
* AbEditCard(card)
* Is called when a card is to be edited, with the card as the parameter.
*
* The following function is only required if ResultsPaneController is used:
*
* goSetMenuValue()
* Core function in globalOverlay.js
*/
// List/card selections in the results pane.
var kNothingSelected = 0;
var kListsAndCards = 1;
var kMultipleListsOnly = 2;
var kSingleListOnly = 3;
var kCardsOnly = 4;
// Global Variables
// gAbView holds an object with an nsIAbView interface
var gAbView = null;
// Holds a reference to the "abResultsTree" document element. Initially
// set up by SetAbView.
var gAbResultsTree = null;
function SetAbView(aURI)
{
// If we don't have a URI, just clear the view and leave everything else
// alone.
if (!aURI) {
gAbView.clearView();
return;
}
// If we do have a URI, we want to allow updating the review even if the
// URI is the same, as the search results may be different.
var sortColumn = kDefaultSortColumn;
var sortDirection = kDefaultAscending;
if (!gAbResultsTree) {
gAbResultsTree = document.getElementById("abResultsTree");
gAbResultsTree.controllers.appendController(ResultsPaneController);
}
if (gAbView) {
sortColumn = gAbView.sortColumn;
sortDirection = gAbView.sortDirection;
}
else {
if (gAbResultsTree.hasAttribute("sortCol"))
sortColumn = gAbResultsTree.getAttribute("sortCol");
var sortColumnNode = document.getElementById(sortColumn);
if (sortColumnNode && sortColumnNode.hasAttribute("sortDirection"))
sortDirection = sortColumnNode.getAttribute("sortDirection");
}
var directory = GetDirectoryFromURI(aURI);
if (!gAbView)
gAbView = Cc["@mozilla.org/addressbook/abview;1"]
.createInstance(Ci.nsIAbView);
var actualSortColumn = gAbView.setView(directory, GetAbViewListener(),
sortColumn, sortDirection);
gAbResultsTree.treeBoxObject.view =
gAbView.QueryInterface(Ci.nsITreeView);
UpdateSortIndicators(actualSortColumn, sortDirection);
// If the selected address book is LDAP and the search box is empty,
// inform the user of the empty results pane.
let abResultsTree = document.getElementById("abResultsTree");
let cardViewOuterBox = document.getElementById("CardViewOuterBox");
let blankResultsPaneMessageBox = document.getElementById("blankResultsPaneMessageBox");
if (aURI.startsWith("moz-abldapdirectory://") && !aURI.includes("?")) {
if (abResultsTree)
abResultsTree.hidden = true;
if (cardViewOuterBox)
cardViewOuterBox.hidden = true;
if (blankResultsPaneMessageBox)
blankResultsPaneMessageBox.hidden = false;
} else {
if (abResultsTree)
abResultsTree.hidden = false;
if (cardViewOuterBox)
cardViewOuterBox.hidden = false;
if (blankResultsPaneMessageBox)
blankResultsPaneMessageBox.hidden = true;
}
}
function CloseAbView()
{
if (gAbView)
gAbView.clearView();
}
function GetOneOrMoreCardsSelected()
{
return (gAbView && (gAbView.selection.getRangeCount() > 0));
}
function GetSelectedAddresses()
{
return GetAddressesForCards(GetSelectedAbCards());
}
function GetNumSelectedCards()
{
try {
return gAbView.selection.count;
}
catch (ex) {
}
// if something went wrong, return 0 for the count.
return 0;
}
function GetSelectedCardTypes()
{
var cards = GetSelectedAbCards();
if (!cards) {
Cu.reportError("ERROR: GetSelectedCardTypes: |cards| is null.");
return kNothingSelected; // no view
}
var count = cards.length;
if (count == 0)
return kNothingSelected; // nothing selected
var mailingListCnt = 0;
var cardCnt = 0;
for (let i = 0; i < count; i++) {
// We can assume no values from GetSelectedAbCards will be null.
if (cards[i].isMailList)
mailingListCnt++;
else
cardCnt++;
}
return (mailingListCnt == 0) ? kCardsOnly :
(cardCnt > 0) ? kListsAndCards :
(mailingListCnt == 1) ? kSingleListOnly :
kMultipleListsOnly;
}
// NOTE, will return -1 if more than one card selected, or no cards selected.
function GetSelectedCardIndex()
{
if (!gAbView)
return -1;
var treeSelection = gAbView.selection;
if (treeSelection.getRangeCount() == 1) {
var start = new Object;
var end = new Object;
treeSelection.getRangeAt(0, start, end);
if (start.value == end.value)
return start.value;
}
return -1;
}
// NOTE, returns the card if exactly one card is selected, null otherwise
function GetSelectedCard()
{
var index = GetSelectedCardIndex();
return (index == -1) ? null : gAbView.getCardFromRow(index);
}
/**
* Return a (possibly empty) list of cards
*
* It pushes only non-null/empty element, if any, into the returned list.
*/
function GetSelectedAbCards()
{
var abView = gAbView;
// if sidebar is open, and addressbook panel is open and focused,
// then use the ab view from sidebar (gCurFrame is from sidebarOverlay.js)
if (document.getElementById("sidebar-box")) {
const abPanelUrl =
"chrome://messenger/content/addressbook/addressbook-panel.xul";
if (gCurFrame &&
gCurFrame.getAttribute("src") == abPanelUrl &&
document.commandDispatcher.focusedWindow == gCurFrame.contentDocument.defaultView)
abView = gCurFrame.contentDocument.defaultView.gAbView;
}
if (!abView)
return [];
let cards = [];
var count = abView.selection.getRangeCount();
var current = 0;
for (let i = 0; i < count; ++i) {
let start = {};
let end = {};
abView.selection.getRangeAt(i, start, end);
for (let j = start.value; j <= end.value; ++j) {
// avoid inserting null element into the list. GetRangeAt() may be buggy.
let tmp = abView.getCardFromRow(j);
if (tmp) {
cards.push(tmp);
}
}
}
return cards;
}
// XXX todo
// an optimization might be to make this return
// the selected ranges, which would be faster
// when the user does large selections, but for now, let's keep it simple.
function GetSelectedRows()
{
var selectedRows = "";
if (!gAbView)
return selectedRows;
var rangeCount = gAbView.selection.getRangeCount();
for (let i = 0; i < rangeCount; ++i) {
var start = new Object;
var end = new Object;
gAbView.selection.getRangeAt(i, start, end);
for (let j = start.value;j <= end.value; ++j) {
if (selectedRows)
selectedRows += ",";
selectedRows += j;
}
}
return selectedRows;
}
function AbSwapFirstNameLastName()
{
if (gAbView)
gAbView.swapFirstNameLastName();
}
function AbEditSelectedCard()
{
AbEditCard(GetSelectedCard());
}
function AbResultsPaneOnClick(event)
{
// we only care about button 0 (left click) events
if (event.button != 0) return;
// all we need to worry about here is double clicks
// and column header clicks.
//
// we get in here for clicks on the "treecol" (headers)
// and the "scrollbarbutton" (scrollbar buttons)
// we don't want those events to cause a "double click"
var t = event.originalTarget;
if (t.localName == "treecol") {
var sortDirection;
var currentDirection = t.getAttribute("sortDirection");
// Revert the sort order. If none is set, use Ascending.
sortDirection = currentDirection == kDefaultAscending ?
kDefaultDescending : kDefaultAscending;
SortAndUpdateIndicators(t.id, sortDirection);
}
else if (t.localName == "treechildren") {
// figure out what row the click was in
var row = gAbResultsTree.treeBoxObject.getRowAt(event.clientX,
event.clientY);
if (row == -1)
return;
if (event.detail == 2)
AbResultsPaneDoubleClick(gAbView.getCardFromRow(row));
}
}
function AbSortAscending()
{
var sortColumn = gAbResultsTree.getAttribute("sortCol");
SortAndUpdateIndicators(sortColumn, kDefaultAscending);
}
function AbSortDescending()
{
var sortColumn = gAbResultsTree.getAttribute("sortCol");
SortAndUpdateIndicators(sortColumn, kDefaultDescending);
}
function SortResultPane(sortColumn)
{
var sortDirection = kDefaultAscending;
if (gAbView)
sortDirection = gAbView.sortDirection;
SortAndUpdateIndicators(sortColumn, sortDirection);
}
function SortAndUpdateIndicators(sortColumn, sortDirection)
{
UpdateSortIndicators(sortColumn, sortDirection);
if (gAbView)
gAbView.sortBy(sortColumn, sortDirection);
}
function UpdateSortIndicators(colID, sortDirection)
{
var sortedColumn = null;
// set the sort indicator on the column we are sorted by
if (colID) {
sortedColumn = document.getElementById(colID);
if (sortedColumn) {
sortedColumn.setAttribute("sortDirection",sortDirection);
gAbResultsTree.setAttribute("sortCol", colID);
}
}
// remove the sort indicator from all the columns
// except the one we are sorted by
var currCol = gAbResultsTree.firstChild.firstChild;
while (currCol) {
if (currCol != sortedColumn && currCol.localName == "treecol")
currCol.removeAttribute("sortDirection");
currCol = currCol.nextSibling;
}
}
function InvalidateResultsPane()
{
if (gAbResultsTree)
gAbResultsTree.treeBoxObject.invalidate();
}
// Controller object for Results Pane
var ResultsPaneController =
{
supportsCommand: function(command)
{
switch (command) {
case "cmd_selectAll":
case "cmd_delete":
case "button_delete":
case "cmd_printcardpreview":
case "cmd_printcard":
case "cmd_properties":
case "cmd_newlist":
case "cmd_newCard":
return true;
default:
return false;
}
},
isCommandEnabled: function(command)
{
switch (command) {
case "cmd_selectAll":
return true;
case "cmd_delete":
case "button_delete":
var numSelected;
var enabled = false;
if (gAbView && gAbView.selection) {
if (gAbView.directory)
enabled = !gAbView.directory.readOnly;
numSelected = gAbView.selection.count;
}
else
numSelected = 0;
// fix me, don't update on isCommandEnabled
if (command == "cmd_delete") {
switch (GetSelectedCardTypes()) {
case kSingleListOnly:
goSetMenuValue(command, "valueList");
break;
case kMultipleListsOnly:
goSetMenuValue(command, "valueLists");
break;
case kListsAndCards:
goSetMenuValue(command, "valueItems");
break;
case kCardsOnly:
default:
if (numSelected < 2)
goSetMenuValue(command, "valueCard");
else
goSetMenuValue(command, "valueCards");
break;
}
}
return (enabled && (numSelected > 0));
case "cmd_printcardpreview":
case "cmd_printcard":
return (GetNumSelectedCards() > 0);
case "cmd_properties":
// Temporary fix for SeaMonkey (see bug 1318852).
// goSetLabelAccesskeyTooltiptext() is only defined in mail/.
// This will be removed in due course and therefore the
// block wasn't indented.
if (typeof goSetLabelAccesskeyTooltiptext == "function") {
let labelAttr = "valueGeneric";
let accKeyAttr = "valueGenericAccessKey";
let tooltipTextAttr = "valueGenericTooltipText";
switch (GetSelectedCardTypes()) {
// Set cmd_properties UI according to the type of the selected item(s),
// even with multiple selections for which cmd_properties is
// not yet available and hence disabled.
case kMultipleListsOnly:
case kSingleListOnly:
labelAttr = "valueMailingList";
accKeyAttr = "valueMailingListAccessKey";
tooltipTextAttr = "valueMailingListTooltipText";
break;
case kCardsOnly:
labelAttr = "valueContact";
accKeyAttr = "valueContactAccessKey";
tooltipTextAttr = "valueContactTooltipText";
break;
case kListsAndCards:
default:
//use generic set of attributes declared above
break;
}
// This code is shared between main AB and composition's contacts sidebar.
// Note that in composition, there's no cmd_properties-button (yet);
// the resulting dump() should be ignored.
goSetLabelAccesskeyTooltiptext("cmd_properties-button", null, null,
tooltipTextAttr);
goSetLabelAccesskeyTooltiptext("cmd_properties-contextMenu",
labelAttr, accKeyAttr);
goSetLabelAccesskeyTooltiptext("cmd_properties-menu",
labelAttr, accKeyAttr);
}
// While "Edit Contact" dialogue is still modal (bug 115904, bug 135126),
// only enable "Properties" button for single selection; then fix bug 119999.
return (GetNumSelectedCards() == 1);
case "cmd_newlist":
case "cmd_newCard":
return true;
default:
return false;
}
},
doCommand: function(command)
{
switch (command) {
case "cmd_selectAll":
if (gAbView)
gAbView.selectAll();
break;
case "cmd_delete":
case "button_delete":
AbDelete();
break;
case "cmd_properties":
AbEditSelectedCard();
break;
case "cmd_newlist":
AbNewList();
break;
case "cmd_newCard":
AbNewCard();
break;
}
},
onEvent: function(event)
{
// on blur events set the menu item texts back to the normal values
if (event == "blur")
goSetMenuValue("cmd_delete", "valueDefault");
}
};
function SelectFirstCard()
{
if (gAbView && gAbView.selection && (gAbView.selection.count > 0))
gAbView.selection.select(0);
}