/* INSERT OPEN OEONE LICENSE */ /***** contactsSelectAddresses * AUTHORS * Mark Wood * * REQUIRED INCLUDES * * NOTES * Code for the 'Select Addresses' dialog called from * an email compose dialog * * IMPLEMENTATION NOTES * ********** */ /** Dialog elements */ const kADDRESS_BOOK_MENU_LIST = "addressBookList"; const kADDRESS_BOOK_MENU_POPUP = "addressBookList-menupopup"; const kCONTACT_CARDS_TREE = "abResultsTree"; const kMAIL_TO_COMMAND_ID_TO = "addToAddress"; const kMAIL_TO_COMMAND_ID_CC = "addCcAddress"; const kMAIL_TO_COMMAND_ID_BCC = "addBccAddress"; const kREMOVE_ADDRESS_COMMAND_ID = "removeAddress"; const kRECIPIENT_LIST_TREE = "addressBucket"; const kRECIPIENT_LIST_TREE_CHILDREN = "bucketBody"; const kRECIPIENT_LIST_CELL_ATTRIBUTE_ADDRESS_PREFIX = "addressPrefix"; const kRECIPIENT_LIST_CELL_ATTRIBUTE_EMAIL = "email"; /** Event dialog elements */ const kINVITE_COMMAND_ID = "addToInviteList"; const kINVITE_REMOVE_COMMAND_ID = "removeFromInviteList"; const kINVITE_LIST_CELL_ATTRIBUTE_CARD_ID = "contactId"; const kINVITE_LIST_ITEM_ATTRIBUTE_CARD_ID = "contactId"; /** Address prefixes */ const kADDRESS_PREFIX_TO = "to"; const kADDRESS_PREFIX_CC = "cc"; const kADDRESS_PREFIX_BCC = "bcc"; /** Global instance of Contact card tree */ var gContactsTree; /** Global instance of Contacts Datasource */ var gContactsDataSource; /** Command arrays */ var gMailToCommandsArray; var gRemoveCommandsArray; var gInviteCommandsArray; var gInviteRemoveCommandsArray; /** Global instance of RDF service */ var gRdf = Components.classes[ "@mozilla.org/rdf/rdf-service;1" ].getService( Components.interfaces.nsIRDFService ); if( Components.classes[ "@mozilla.org/messenger/headerparser;1" ] ) var gHeaderParser = Components.classes[ "@mozilla.org/messenger/headerparser;1" ].getService( Components.interfaces.nsIMsgHeaderParser ); /** Global refs to original composer window */ var gMsgCompFields = 0; var gComposeWindow; var gTopWindow; /** Array of nsIAbCards for attaching to event */ var gEventCardArray = new Array(); /***** onLoadSelectAddresses * METHODS * onLoadSelectAddresses: initializes the select addresses dialog * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function onLoadSelectAddresses() { // Set the dialog buttons setupOkCancelButtons( selectAddressesOkButton, 0 ); // Setup the the address book chooser setupAddressBookChooser(); // Setup the commands initCommands(); if( window.arguments && window.arguments[ 0 ] ) { // Get the Contacts Data Source gContactsDataSource = window.arguments[ 0 ].contactsDataSource; // Get the uri of the first address book in the chooser var bookUri = document.getElementById( kADDRESS_BOOK_MENU_LIST ).getAttribute( "value" ); // Generate the cardset for the specified book //updateCardSet( gContactsDataSource, bookUri ); updateSelectAddressesCardSet( gContactsDataSource, bookUri ) // Get the compose window and associated elements var toAddress = "", ccAddress = "", bccAddress = ""; gComposeWindow = window.arguments[0].composeWindow; gMsgCompFields = window.arguments[ 0 ].msgCompFields; gTopWindow = window.arguments[ 0 ].topWindow; toAddress = window.arguments[ 0 ].toAddress; ccAddress = window.arguments[ 0 ].ccAddress; bccAddress = window.arguments[ 0 ].bccAddress; // Add any existing addresses to the recipient list addAddressFromComposeWindow( toAddress, DTD_toPrefix, kADDRESS_PREFIX_TO ); addAddressFromComposeWindow( ccAddress, DTD_ccPrefix, kADDRESS_PREFIX_CC ); addAddressFromComposeWindow( bccAddress, DTD_bccPrefix, kADDRESS_PREFIX_BCC ); } } // End function onLoadSelectAddresses /***** addAddressFromComposeWindow * METHODS * addAddressFromComposeWindow: adds existing addresses from the * compose window to the list of * recipients * * PARAMETERS * addresses: comma-separated list of email addresses * displayPrefix: prefix to display with addresses * addressPrefix: mailto prefix to use with addresses * * RETURN VALUE * None * * NOTES ********** */ function addAddressFromComposeWindow( addresses, displayPrefix, addressPrefix ) { if( addresses.length > 0 ) { var addressArray = addresses.split(","); for( var index = 0; index < addressArray.length; index++ ) { // remove leading spaces while ( addressArray[index][0] == " " ) { addressArray[ index ] = addressArray[ index ].substring( 1, addressArray[ index ].length ); } addAddressIntoBucket( addressPrefix, ( displayPrefix + addressArray[ index ] ), addressArray[ index ] ); } } } // End function addAddressFromComposeWindow /***** setupAddressBookChooser * METHODS * setupAddressBookChooser: initializes the address book chooser * by selecting the first address book * in the list * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function setupAddressBookChooser() { // Select the first item in the menulist var addressBookChooser = document.getElementById( kADDRESS_BOOK_MENU_LIST ); if( addressBookChooser ) { // Default to the first valid addressbook when none is // selected. (the 0th is an empty/invalid entry) var menupopup = document.getElementById( kADDRESS_BOOK_MENU_POPUP ); addressBookChooser.label = menupopup.childNodes[ 1 ].getAttribute( "label" ); addressBookChooser.value = menupopup.childNodes[ 1 ].getAttribute( "value" ); } } // End function setupAddressBookChooser /***** onChooseAddressBook * METHODS * onChooseAddressBook: called when an address book is selected * from the address book chooser * * PARAMETERS * addressBookMenuList: menulist item containing address book ids * * RETURN VALUE * None * * NOTES ********** */ function onChooseAddressBook( addressBookListMenuList ) { // Get the uri of the selected address book var bookUri = addressBookListMenuList.getAttribute( "value" ); // Generate the cardset for the specified book //updateCardSet( gContactsDataSource, bookUri ); updateSelectAddressesCardSet( gContactsDataSource, bookUri ) // Update the commands updateCommands( gMailToCommandsArray, true ); } // End function onChooseAddressBook /***** updateCardSet * METHODS * updateCardSet: updates the current cardset for the specified * address book uri * * PARAMETERS * dataSource: instance of Contacts datasource * bookUri: uri of specified address book * * RETURN VALUE * None * * NOTES ********** */ function updateCardSet( dataSource, bookUri ) { // Get the card set for the selected address book var targetBook = dataSource.makeAddressBook( bookUri ); var cardSet = dataSource.makeCardSet( "GeneratedName", "ascending" ); cardSet.initWithAddressBookUri( targetBook.getBookUri() ); // Setup the tree displaying the contacts for the selected address book //gContactsTree = new ContactsTree( cardSet ); return cardSet; } // End function updateCardSet function updateSelectAddressesCardSet( dataSource, bookUri ) { var cardSet = updateCardSet( dataSource, bookUri ); gContactsTree = new ContactsTree( cardSet ); } function updateEventCardSet( dataSource, bookUri ) { var cardSet = updateCardSet( dataSource, bookUri ); gContactsTree = new EventContactsTree( cardSet ); } /***** ContactsTree * METHODS * ContactsTree: definition for tree used to display contact cards * * PARAMETERS * cardSet: CardSet object containing cards for selected address book * * RETURN VALUE * None * * NOTES ********** */ function ContactsTree( cardSet ) { this.cardSet = cardSet; this.resultsTree = document.getElementById( kCONTACT_CARDS_TREE ); this.resultsTree.treeBoxObject.view = this; this.resultsTree.contactsTree = this; this.atomRowEnabled = makeAtom( "enabled" ); this.atomRowDisabled = makeAtom( "disabled" ); } // End ContactsTree definition /***** ContactsTree * METHODS * Method definition for ContactsTree object * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ ContactsTree.prototype = { // TREE Functions mTree: null, mSelection: null, get rowCount() { return this.cardSet.cardList.length; }, get selection() { return this.mSelection; }, set selection(aSelection) { this.mSelection = aSelection; }, setTree: function(aTree) { this.mTree = aTree; }, getCellText: function(aRow, aColId) { var card = this.cardSet.cardList[ aRow ]; if( card ) { if( aColId == "PrimaryEmail" && !card.isMailList() ) { if( card.getCardValue( aColId ).length == 0 ) { return DTD_noEmailMessage; } else { return card.getCardValue( aColId ); } } else { return card.getCardValue( aColId ); } } else { return ""; } }, getRowProperties: function(aIndex, aProperties) { var card = this.cardSet.cardList[ aIndex ]; if( !card.isMailList() ) { if( card.getCardValue( "PrimaryEmail" ) == "" ) { aProperties.AppendElement( this.atomRowDisabled ); } else { aProperties.AppendElement( this.atomRowEnabled ); } } }, getCellProperties: function(aRow, aColId, aProperties) { var card = this.cardSet.cardList[ aRow ]; if( !card.isMailList() ) { if( card.getCardValue( "PrimaryEmail" ) == "" ) { aProperties.AppendElement( this.atomRowDisabled ); } else { aProperties.AppendElement( this.atomRowEnabled ); } } }, getColumnProperties: function(aColId, aColElt, aProperties) {}, getParentIndex: function(aRowIndex) { return -1; }, //hasNextSibling: function(aRowIndex, aAfterIndex) { }, getLevel: function(aIndex) { return 0; }, getImageSrc: function(aRow, aColId) {}, //getProgressMode: function(aRow, aColId) {}, //getCellValue: function(aRow, aColId) {}, isContainer: function(aIndex) { return false; }, //isContainerOpen: function(aIndex) {}, //isContainerEmpty: function(aIndex) {}, isSeparator: function(aIndex) { return false; }, isSorted: function() {}, //toggleOpenState: function(aIndex) {}, selectionChanged: function() { }, cycleHeader: function(aColId, aElt) {}, //cycleCell: function(aRow, aColId) {}, //isEditable: function(aRow, aColId) {}, setCellText: function(aRow, aColId, aValue) {}, //performAction: function(aAction) {}, //performActionOnRow: function(aAction, aRow) {}, //performActionOnCell: function(aAction, aRow, aColId) {}, // extra utility stuff setSelection : function( selList ) { this.selection.clearSelection(); for( var i = 0; i < selList.length; ++i ) { this.selection.rangedSelect( selList[i], selList[i], true ); } }, getSelectedCardIndexes : function( ) { var selectedCardIndexes = new Array( this.selection.count ); var count = this.selection.getRangeCount(); var current = 0; var start = new Object(); var end = new Object(); for( var i = 0; i < count; i++) { this.selection.getRangeAt(i,start,end); for( var j = start.value; j <= end.value; j++ ) { selectedCardIndexes[current] = j; current++; } } return selectedCardIndexes; }, onMouseDown : function( 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 target = event.originalTarget; if (target.localName == "treecol") { var columnSortField = target.getAttribute( "sort-field" ); sortAndUpdateIndicators( columnSortField ); } else if (target.localName == "treechildren") { var row = new Object(); this.recipientTreeElement.treeBoxObject.getCellAt( event.clientX, event.clientY, row, {}, {} ); if( row.value != -1 && row.value < this.recipientTreeElement.view.rowCount ) { var card = this.cardSet.cardList[ row.value ]; if( card.getPrimaryEmail() != "" ) { card._checked = !card._checked; this.recipientTreeElement.treeBoxObject.invalidateRow( row.value ); } } } }, onClick: function( event ) { // Get the target var target = event.originalTarget; if( target.localName == "treechildren" ) { // Get the email address of the card just clicked var row = new Object(); this.resultsTree.treeBoxObject.getCellAt( event.clientX, event.clientY, row, {}, {} ); if( row.value != -1 ) { var card = this.cardSet.cardList[ row.value ]; // If the card has no email address, remove it from the selection if( card && ( !card.isMailList() ) && ( card.getCardValue( "PrimaryEmail" ) == "" ) ) { this.selection.clearRange( row.value, row.value ); return; } if( this.getSelectedCardIndexes().length > 0 ) { updateCommands( gMailToCommandsArray, false ); } else { updateCommands( gMailToCommandsArray, true ); } } } }, // If an address is double clicked, add it to the list as a 'To' address onDblClick: function( event ) { addSelectedAddressesIntoBucket( DTD_toPrefix, kADDRESS_PREFIX_TO ); } }; function makeAtom( aVal ) { var svc = Components.classes[ "@mozilla.org/atom-service;1" ].getService( Components.interfaces.nsIAtomService ); return svc.getAtom(aVal); } /***** initCommands * METHODS * initCommands: calls all required command initializers * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function initCommands() { initMailToCommands(); initRemoveCommands(); } // End function initCommands /***** initMailToCommands * METHODS * initMailToCommands: initializes the commands associated with * selecting existing contacts * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function initMailToCommands() { gMailToCommandsArray = new Array( kMAIL_TO_COMMAND_ID_TO, kMAIL_TO_COMMAND_ID_CC, kMAIL_TO_COMMAND_ID_BCC ); } // End function initMailToCommands /***** initRemoveCommands * METHODS * initRemoveCommands: initializes the commands associated with * selecting recipients * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function initRemoveCommands() { gRemoveCommandsArray = new Array( kREMOVE_ADDRESS_COMMAND_ID ); } // End function initRemoveCommands /***** updateCommands * METHODS * updateCommands: updates specified commands associated with * specified status * * PARAMETERS * commandsArray: Array containing command ids * disableStatus: true to disable commands, false to enable * * RETURN VALUE * None * * NOTES ********** */ function updateCommands( commandsArray, disableStatus ) { if( commandsArray ) { var element; for( var index = 0; index < commandsArray.length; index++ ) { element = document.getElementById( commandsArray[ index ] ); if( element ) { element.setAttribute( "disabled", disableStatus ); } } } } // End function updateCommands /***** addSelectedAddressesIntoBucket * METHODS * addSelectedAddressesIntoBucket: adds the selected addresses to the * recipient list using the specified * prefix * * PARAMETERS * displayPrefix: display prefix to use with selected addresses * addressPrefix: address prefix to use with selected addresses * * RETURN VALUE * None * * NOTES ********** */ function addSelectedAddressesIntoBucket( displayPrefix, addressPrefix ) { addSelectedCardsToBucket( displayPrefix, addressPrefix ); // Clear selection and update mailto commands gContactsTree.resultsTree.treeBoxObject.selection.clearSelection(); updateCommands( gMailToCommandsArray, true ); } // End function addSelectedAddressesIntoBucket function addSelectedCardsToBucket( displayPrefix, addressPrefix ) { var cards = getSelectedCards(); var count = cards.length; for( var i = 0; i < count; i++ ) { addCardIntoBucket( displayPrefix, addressPrefix, cards[ i ] ); } } function addSelectedInviteCardsToBucket( displayPrefix, addressPrefix ) { var cards = getSelectedCards(); var count = cards.length; var cardId; for( var i = 0; i < count; i++ ) { var address = displayPrefix + getAddressFromCard( cards[ i ] ); if( !cards[ i ].isMailList ) { // Add the card to the display cardId = generateCardId( cards[ i ] ); addInviteAddressIntoBucket( address, cardId ); // Add to the event card array as well gEventCardArray[ cardId ] = cards[ i ]; } } } /***** generateCardId * METHODS * generateCardId: returns a unique card id using the key of the * specified nsIAbCard and its associated * address book id * * PARAMETERS * card: instance of nsIAbCard * [ bookId ]: uri of associated address book; uses current book if none specified * * RETURN VALUE * String: unique card identifier * * NOTES ********** */ function generateCardId( card, bookId ) { var cardId; // If no bookId specified, get the current address book uri if( !bookId ) { bookId = document.getElementById( kADDRESS_BOOK_MENU_LIST ).getAttribute( "value" ); } cardId = bookId + "/Card" + card.key; return cardId; } // End function generateCardId /***** addCardIntoBucket * METHODS * addCardIntoBucket: adds the specified card to the recipient * list with the specified prefix * * PARAMETERS * displayPrefix: address prefix to display * addressPrefix: address prefix to use * card: nsIAbCard to add to recipient list * * RETURN VALUE * None * * NOTES ********** */ function addCardIntoBucket( displayPrefix, addressPrefix, card ) { var address = displayPrefix + getAddressFromCard( card ); if( card.isMailList ) { addAddressIntoBucket( addressPrefix, address, getAddressFromCard( card ) ); } else { addAddressIntoBucket( addressPrefix, address, card.primaryEmail ); } } // End function addCardIntoBucket function getAddressFromCard( card ) { var email; if( card.isMailList ) { var directory = getDirectoryFromURI(card.mailListURI); if( directory.description ) { email = directory.description; } else { email = card.displayName; } } else { email = card.primaryEmail; } email = gHeaderParser.makeFullAddressWString( card.displayName, email ); return email; } function getDirectoryFromURI( uri ) { var directory = gRdf.GetResource( uri ).QueryInterface( Components.interfaces.nsIAbDirectory ); return directory; } /***** getSelectedCards * METHODS * getSelectedCards: returns an array of selected address cards * * PARAMETERS * None * * RETURN VALUE * Array containing address cards * * NOTES ********** */ function getSelectedCards() { var cards = new Array(); var selectedIndexes = gContactsTree.getSelectedCardIndexes(); if( selectedIndexes.length > 0 ) { for( var index = 0; index < selectedIndexes.length; index++ ) { cards.push( gContactsTree.cardSet.cardList[ selectedIndexes[ index ] ].abCard ); } } return cards; } // End function getSelectedCards /***** addAddressIntoBucket * METHODS * addAddressIntoBucket: add the address to the recipient * display * * PARAMETERS * addressPrefix: address prefix to use * displayAddress: address that gets displayed in recipient list * email: email address to use * * RETURN VALUE * None * * NOTES ********** */ function addAddressIntoBucket( addressPrefix, displayAddress, email ) { var body = document.getElementById( kRECIPIENT_LIST_TREE_CHILDREN ); var item = document.createElement( "treeitem" ); var row = document.createElement( "treerow" ); var cell = document.createElement( "treecell" ); cell.setAttribute( "label", displayAddress ); cell.setAttribute( kRECIPIENT_LIST_CELL_ATTRIBUTE_EMAIL, email ); cell.setAttribute( kRECIPIENT_LIST_CELL_ATTRIBUTE_ADDRESS_PREFIX, addressPrefix ); row.appendChild( cell ); item.appendChild( row ); body.appendChild( item ); } // End function addAddressIntoBucket /***** addInviteAddressIntoBucket * METHODS * addInviteAddressIntoBucket: add the address to the invite list * * PARAMETERS * displayAddress: address that gets displayed in invite list * cardId: unique identifier of associated card in gEventCardArray * * RETURN VALUE * None * * NOTES ********** */ function addInviteAddressIntoBucket( displayAddress, cardId ) { var body = document.getElementById( kRECIPIENT_LIST_TREE_CHILDREN ); var item = document.createElement( "treeitem" ); var row = document.createElement( "treerow" ); var cell = document.createElement( "treecell" ); cell.setAttribute( "label", displayAddress ); item.setAttribute( kINVITE_LIST_ITEM_ATTRIBUTE_CARD_ID, cardId ); row.appendChild( cell ); item.appendChild( row ); body.appendChild( item ); } // End function addInviteAddressIntoBucket /***** selectRecipient * METHODS * selectRecipient: called when a recipient is selected or * unselected; used to update appropriate * commands * * PARAMETERS * tree: XUL tree containing recipients * * RETURN VALUE * None * * NOTES ********** */ function selectRecipient( tree ) { var selectedItems = getSelectedRecipients( tree ); if( selectedItems.length > 0 ) { updateCommands( gRemoveCommandsArray, false ); } else { updateCommands( gRemoveCommandsArray, true ); } } // End function selectRecipient function getSelectedRecipients( tree ) { var selectedItems = new Array(); if( tree && tree.treeBoxObject && tree.treeBoxObject.selection ) { var rangeCount = tree.treeBoxObject.selection.getRangeCount(); for( var i = 0; i < rangeCount; i++ ) { var startIndex = new Object(); var endIndex = new Object(); tree.treeBoxObject.selection.getRangeAt( i, startIndex, endIndex ); for( var j = startIndex.value; j <= endIndex.value; j++ ) { selectedItems.push( tree.treeBoxObject.view.getItemAtIndex( j ) ); } } } return selectedItems; } /***** removeSelectedFromBucket * METHODS * removeSelectedFromBucket: removes selected items from the * specified tree * * PARAMETERS * bucketTree: XUL tree containing selected items * * RETURN VALUE * None * * NOTES ********** */ function removeSelectedFromBucket( bucketTree ) { if( bucketTree ) { var body = document.getElementById( kRECIPIENT_LIST_TREE_CHILDREN ); var selection = bucketTree.view.selection; var rangeCount = selection.getRangeCount(); for( i = rangeCount-1; i >= 0; --i ) { var start = {}, end = {}; selection.getRangeAt( i, start, end ); for( j = end.value; j >= start.value; --j ) { var item = bucketTree.contentView.getItemAtIndex( j ); body.removeChild( item ); } } } } // End function removeSelectedFromBucket /***** removeSelectedFromRecipientBucket * METHODS * removeSelectedFromRecipientBucket: removes selected addresses * from recipient list * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function removeSelectedFromRecipientBucket() { // Remove selected items from recipient list var bucketTree = document.getElementById( kRECIPIENT_LIST_TREE ); removeSelectedFromBucket( bucketTree ); // Disable remove command updateCommands( gRemoveCommandsArray, true ); } // End function removeSelectedFromRecipientBucket /***** selectAddressesOkButton * METHODS * selectAddressesOkButton: adds the selected recipients to the * compose window and closes the select * addresses dialog * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function selectAddressesOkButton() { var body = document.getElementById( kRECIPIENT_LIST_TREE_CHILDREN ); var item, row, cell, text, mailPrefix, colon, email; var toAddress = "", ccAddress = "", bccAddress = "", emptyEmail = ""; for( var index = 0; index < body.childNodes.length; index++ ) { item = body.childNodes[index]; if( item.childNodes && item.childNodes.length ) { row = item.childNodes[ 0 ]; if( row.childNodes && row.childNodes.length ) { cell = row.childNodes[0]; mailPrefix = cell.getAttribute( kRECIPIENT_LIST_CELL_ATTRIBUTE_ADDRESS_PREFIX ); text = cell.getAttribute( "label" ); email = cell.getAttribute( kRECIPIENT_LIST_CELL_ATTRIBUTE_EMAIL ); if( mailPrefix ) { switch( mailPrefix ) { case kADDRESS_PREFIX_TO: toAddress += email + ","; break; case kADDRESS_PREFIX_CC: ccAddress += email + ","; break; case kADDRESS_PREFIX_BCC: bccAddress += email + ","; break; } } if(!email) { if (emptyEmail) { emptyEmail +=", "; } emptyEmail += text.substring(prefixTo.length, text.length-2); } } } } if(emptyEmail) { var alertText = gAddressBookBundle.getString("emptyEmailCard"); alert(alertText + emptyEmail); return false; } // Trim any trailing commas from the address lists if( toAddress[ toAddress.length - 1 ] == "," ) { toAddress = toAddress.substring( 0, ( toAddress.length - 1 ) ); } if( ccAddress[ ccAddress.length - 1 ] == "," ) { ccAddress = ccAddress.substring( 0, ( ccAddress.length - 1 ) ); } if( bccAddress[ bccAddress.length - 1 ] == "," ) { bccAddress = bccAddress.substring( 0, ( bccAddress.length - 1 ) ); } // reset the UI in compose window gMsgCompFields.to = toAddress; gMsgCompFields.cc = ccAddress; gMsgCompFields.bcc = bccAddress; gTopWindow.CompFields2Recipients( gMsgCompFields ); // Return true to close OE dialog return true; } // End function selectAddressesOkButton /***** onLoadEventDialog * METHODS * onLoadEventDialog: initializes the 'Contacts' portion of the * Calendar Event dialog * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function onLoadEventDialog() { // Get the Contacts Data Source gContactsDataSource = pendialog.getService( "org.penzilla.contacts" ).contactsDataSource; // Store any existing attached cards in the event card array initializeContactsArray(); // Display any existing attached contacts setupAttachedContacts( gEventCardArray ); // Setup the the address book chooser setupAddressBookChooser(); // Setup the commands initEventAddressesCommands(); // Get the uri of the first address book in the chooser var bookUri = document.getElementById( kADDRESS_BOOK_MENU_LIST ).getAttribute( "value" ); // Generate the cardset for the specified book updateEventCardSet( gContactsDataSource, bookUri ); } // End function onLoadEventDialog function getAddressBookDatabase( bookId ) { var book = Components.classes[ "@mozilla.org/addressbook;1" ].createInstance( Components.interfaces.nsIAddressBook ); var bookDatabase = book.getAbDatabaseFromURI( bookId ); return bookDatabase; } /***** initializeContactsArray * METHODS * initializeContactsArray: initalizes the contacts with any * existing contacts attached to the * event * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function initializeContactsArray() { var contactsArray = gEvent.contactsArray; if( contactsArray ) { var bookId; var cardId; var card; var mdbCard; for( var i = 0; i < contactsArray.Count(); i++ ) { card = contactsArray.QueryElementAt( i, Components.interfaces.nsIAbCard ); mdbCard = contactsArray.QueryElementAt( i, Components.interfaces.nsIAbMDBCard ); bookId = getBookId( card ); cardId = generateCardId( mdbCard, bookId ); gEventCardArray[ cardId ] = card; } } } // End function initializeContactsArray /***** getBookId * METHODS * getBookId: returns the uri of the containing address book * of the specified card * * PARAMETERS * card: instance of nsIAbCard * * RETURN VALUE * String: uri of containing address book * * NOTES * nsIAbCard instances no longer contain a unique key across * address books, only a key within their book. To figure out * where it belongs, this goes through all the existing books * and determines where the card belongs. If there is a simpler * way to do this, please implement it. This is done when displaying * existing attached contacts in an event to get a unique id and avoid * adding duplicates and to remove the correct contact from the array * Mark Wood, July 23, 2002 ********** */ function getBookId( card ) { // Go through all the address books until a match is found var addressBookList = gContactsDataSource.getAllAddressBookUris(); var bookDatabase; var bookId; for( var i = 0; i < addressBookList.length; i++ ) { bookDatabase = getAddressBookDatabase( addressBookList[ i ] ); if( bookDatabase && bookDatabase.containsCard( card ) ) { bookId = addressBookList[ i ]; break; } } return bookId; } // End function getBookId /***** EventContactsTree * METHODS * EventContactsTree: definition for tree used to display contact cards * * PARAMETERS * cardSet: CardSet object containing cards for selected address book * * RETURN VALUE * None * * NOTES ********** */ function EventContactsTree( cardSet ) { this.cardSet = cardSet; this.resultsTree = document.getElementById( kCONTACT_CARDS_TREE ); this.resultsTree.treeBoxObject.view = this; this.resultsTree.contactsTree = this; this.atomRowEnabled = makeAtom( "enabled" ); this.atomRowDisabled = makeAtom( "disabled" ); } // End EventContactsTree definition /***** EventContactsTree * METHODS * Method definition for EventContactsTree object * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ EventContactsTree.prototype = { // TREE Functions mTree: null, mSelection: null, get rowCount() { return this.cardSet.cardList.length; }, get selection() { return this.mSelection; }, set selection(aSelection) { this.mSelection = aSelection; }, setTree: function(aTree) { this.mTree = aTree; }, getCellText: function(aRow, aColId) { var card = this.cardSet.cardList[ aRow ]; if( card ) { if( aColId == "PrimaryEmail" && !card.isMailList() ) { if( card.getCardValue( aColId ).length == 0 ) { return DTD_noEmailMessage; } else { return card.getCardValue( aColId ); } } else { return card.getCardValue( aColId ); } } else { return ""; } }, getRowProperties: function(aIndex, aProperties) { var card = this.cardSet.cardList[ aIndex ]; if( !card.isMailList() ) { if( card.getCardValue( "PrimaryEmail" ) == "" ) { aProperties.AppendElement( this.atomRowDisabled ); } else { aProperties.AppendElement( this.atomRowEnabled ); } } }, getCellProperties: function(aRow, aColId, aProperties) { var card = this.cardSet.cardList[ aRow ]; if( !card.isMailList() ) { if( card.getCardValue( "PrimaryEmail" ) == "" ) { aProperties.AppendElement( this.atomRowDisabled ); } else { aProperties.AppendElement( this.atomRowEnabled ); } } }, getColumnProperties: function(aColId, aColElt, aProperties) {}, getParentIndex: function(aRowIndex) { return -1; }, //hasNextSibling: function(aRowIndex, aAfterIndex) { }, getLevel: function(aIndex) { return 0; }, getImageSrc: function(aRow, aColId) {}, //getProgressMode: function(aRow, aColId) {}, //getCellValue: function(aRow, aColId) {}, isContainer: function(aIndex) { return false; }, //isContainerOpen: function(aIndex) {}, //isContainerEmpty: function(aIndex) {}, isSeparator: function(aIndex) { return false; }, isSorted: function() {}, //toggleOpenState: function(aIndex) {}, selectionChanged: function() { }, cycleHeader: function(aColId, aElt) {}, //cycleCell: function(aRow, aColId) {}, //isEditable: function(aRow, aColId) {}, setCellText: function(aRow, aColId, aValue) {}, //performAction: function(aAction) {}, //performActionOnRow: function(aAction, aRow) {}, //performActionOnCell: function(aAction, aRow, aColId) {}, // extra utility stuff setSelection : function( selList ) { this.selection.clearSelection(); for( var i = 0; i < selList.length; ++i ) { this.selection.rangedSelect( selList[i], selList[i], true ); } }, getSelectedCardIndexes : function( ) { var selectedCardIndexes = new Array( this.selection.count ); var count = this.selection.getRangeCount(); var current = 0; var start = new Object(); var end = new Object(); for( var i = 0; i < count; i++) { this.selection.getRangeAt(i,start,end); for( var j = start.value; j <= end.value; j++ ) { selectedCardIndexes[current] = j; current++; } } return selectedCardIndexes; }, onMouseDown : function( 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 target = event.originalTarget; if (target.localName == "treecol") { var columnSortField = target.getAttribute( "sort-field" ); sortAndUpdateIndicators( columnSortField ); } else if (target.localName == "treechildren") { var row = new Object(); this.recipientTreeElement.treeBoxObject.getCellAt( event.clientX, event.clientY, row, {}, {} ); if( row.value != -1 && row.value < this.recipientTreeElement.view.rowCount ) { var card = this.cardSet.cardList[ row.value ]; if( card.getPrimaryEmail() != "" ) { card._checked = !card._checked; this.recipientTreeElement.treeBoxObject.invalidateRow( row.value ); } } } }, onClick: function( event ) { // Get the target var target = event.originalTarget; if( target.localName == "treechildren" ) { // Get the email address of the card just clicked var row = new Object(); this.resultsTree.treeBoxObject.getCellAt( event.clientX, event.clientY, row, {}, {} ); if( row.value != -1 ) { var card = this.cardSet.cardList[ row.value ]; // If the card has no email address, remove it from the selection if( card && ( !card.isMailList() ) && ( card.getCardValue( "PrimaryEmail" ) == "" ) ) { this.selection.clearRange( row.value, row.value ); return; } if( this.getSelectedCardIndexes().length > 0 ) { updateCommands( gInviteCommandsArray, false ); } else { updateCommands( gInviteCommandsArray, true ); } } } }, // If an address is double clicked, add it to the list as a 'To' address onDblClick: function( event ) { addSelectedAddressesIntoInviteBucket( '', '' ); } }; /***** onChooseAddressBook * METHODS * onChooseAddressBook: called when an address book is selected * from the address book chooser * * PARAMETERS * addressBookMenuList: menulist item containing address book ids * * RETURN VALUE * None * * NOTES ********** */ function onChooseAddressBookEventDialog( addressBookListMenuList ) { // Get the uri of the selected address book var bookUri = addressBookListMenuList.getAttribute( "value" ); // Generate the cardset for the specified book updateEventCardSet( gContactsDataSource, bookUri ) // Update the commands updateCommands( gInviteCommandsArray, true ); } // End function onChooseAddressBook /***** initEventAddressesCommands * METHODS * initEventAddressesCommands: calls all required command initializers * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function initEventAddressesCommands() { initInviteCommands(); initRemoveInviteCommands(); } // End function initEventAddressesCommands /***** initInviteCommands * METHODS * initInviteCommands: initializes the commands associated with * selecting contacts to invite to event * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function initInviteCommands() { gInviteCommandsArray = new Array( kINVITE_COMMAND_ID ); } // End function initInviteCommands /***** initRemoveInviteCommands * METHODS * initRemoveInviteCommands: initializes the commands associated * with removing contacts from the invite list * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function initRemoveInviteCommands() { gInviteRemoveCommandsArray = new Array( kINVITE_REMOVE_COMMAND_ID ); } // End function initRemoveInviteCommands /***** selectEventRecipient * METHODS * selectEventRecipient: called when a recipient is selected or * unselected; used to update appropriate * commands * * PARAMETERS * tree: XUL tree containing recipients * * RETURN VALUE * None * * NOTES ********** */ function selectEventRecipient( tree ) { var selectedItems = getSelectedRecipients( tree ); if( selectedItems.length > 0 ) { updateCommands( gInviteRemoveCommandsArray, false ); } else { updateCommands( gInviteRemoveCommandsArray, true ); } } // End function selectEventRecipient /***** addSelectedAddressesIntoInviteBucket * METHODS * addSelectedAddressesIntoInviteBucket: adds the selected addresses * to the recipient list * * PARAMETERS * displayPrefix: display prefix to use with selected addresses * addressPrefix: address prefix to use with selected addresses * * RETURN VALUE * None * * NOTES ********** */ function addSelectedAddressesIntoInviteBucket( displayPrefix, addressPrefix ) { // Add the selected cards addSelectedInviteCardsToBucket( displayPrefix, addressPrefix ); // Clear selection and update mailto commands gContactsTree.resultsTree.treeBoxObject.selection.clearSelection(); updateCommands( gInviteCommandsArray, true ); } // End function addSelectedAddressesIntoInviteBucket /***** removeSelectedFromInviteBucket * METHODS * removeSelectedFromInviteBucket: removes selected addresses from the * invite list * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function removeSelectedFromInviteBucket() { var bucketTree = document.getElementById( kRECIPIENT_LIST_TREE ); // Remove the items from the event card array removeSelectedFromEventArray( bucketTree ); // Remove selected items removeSelectedFromBucket( bucketTree ); // Disable remove command updateCommands( gInviteRemoveCommandsArray, true ); } // End function removeSelectedFromInviteBucket /***** removeSelectedFromEventArray * METHODS * removeSelectedFromEventArray: removes the selected cards in the * invite list from the array of cards * to be attached to the event * * PARAMETERS * None * * RETURN VALUE * None * * NOTES ********** */ function removeSelectedFromEventArray( bucketTree ) { if( bucketTree ) { var body = document.getElementById( kRECIPIENT_LIST_TREE_CHILDREN ); var selection = bucketTree.view.selection; var rangeCount = selection.getRangeCount(); for( i = rangeCount-1; i >= 0; --i ) { var start = {}, end = {}; selection.getRangeAt( i, start, end ); var item; var cardId; for( j = end.value; j >= start.value; --j ) { item = bucketTree.contentView.getItemAtIndex( j ); cardId = item.getAttribute( kINVITE_LIST_ITEM_ATTRIBUTE_CARD_ID ); gEventCardArray[ cardId ] = null; } } } } // End function removeSelectedFromEventArray /***** setupAttachedContacts * METHODS * setupAttachedContacts: display any existing attached contacts * in the dialog * * PARAMETERS * attachedContacts: array of nsIAbCards * * RETURN VALUE * None * * NOTES ********** */ function setupAttachedContacts( attachedContacts ) { var address; for( var cardId in attachedContacts ) { address = "" + getAddressFromCard( attachedContacts[ cardId ] ); addInviteAddressIntoBucket( address, cardId ); } } // End function setupAttachedContacts