summaryrefslogtreecommitdiffstats
path: root/mailnews/addrbook/content/abResultsPane.js
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/addrbook/content/abResultsPane.js')
-rw-r--r--mailnews/addrbook/content/abResultsPane.js502
1 files changed, 502 insertions, 0 deletions
diff --git a/mailnews/addrbook/content/abResultsPane.js b/mailnews/addrbook/content/abResultsPane.js
new file mode 100644
index 000000000..58a1771cb
--- /dev/null
+++ b/mailnews/addrbook/content/abResultsPane.js
@@ -0,0 +1,502 @@
+/* -*- 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 = Components.classes["@mozilla.org/addressbook/abview;1"]
+ .createInstance(Components.interfaces.nsIAbView);
+
+ var actualSortColumn = gAbView.setView(directory, GetAbViewListener(),
+ sortColumn, sortDirection);
+
+ gAbResultsTree.treeBoxObject.view =
+ gAbView.QueryInterface(Components.interfaces.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) {
+ Components.utils.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_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_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);
+}