1 /* ***** BEGIN LICENSE BLOCK ***** 2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 * 4 * The contents of this file are subject to the Mozilla Public License Version 5 * 1.1 (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * http://www.mozilla.org/MPL/ 8 * 9 * Software distributed under the License is distributed on an "AS IS" basis, 10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 * for the specific language governing rights and limitations under the 12 * License. 13 * 14 * The Original Code is gContactSync. 15 * 16 * The Initial Developer of the Original Code is 17 * Josh Geenen <gcontactsync@pirules.org>. 18 * Portions created by the Initial Developer are Copyright (C) 2008-2011 19 * the Initial Developer. All Rights Reserved. 20 * 21 * Contributor(s): 22 * 23 * Alternatively, the contents of this file may be used under the terms of 24 * either the GNU General Public License Version 2 or later (the "GPL"), or 25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 26 * in which case the provisions of the GPL or the LGPL are applicable instead 27 * of those above. If you wish to allow use of your version of this file only 28 * under the terms of either the GPL or the LGPL, and not to allow others to 29 * use your version of this file under the terms of the MPL, indicate your 30 * decision by deleting the provisions above and replace them with the notice 31 * and other provisions required by the GPL or the LGPL. If you do not delete 32 * the provisions above, a recipient may use your version of this file under 33 * the terms of any one of the MPL, the GPL or the LGPL. 34 * 35 * ***** END LICENSE BLOCK ***** */ 36 37 if (!com) var com = {}; // A generic wrapper variable 38 // A wrapper for all GCS functions and variables 39 if (!com.gContactSync) com.gContactSync = {}; 40 41 window.addEventListener("load", 42 /** Initializes the ABOverlay class when the window has finished loading */ 43 function gCS_abOverlayLoadListener(e) { 44 com.gContactSync.ABOverlay.initialize(); 45 }, 46 false); 47 48 /** 49 * The Address Book window overlay overrides certain functions to add 50 * gContactSync fields to the address book. 51 * @class 52 */ 53 com.gContactSync.ABOverlay = { 54 /** 55 * Special links for various IM protocols 56 * Format: Type (from Google): protocol 57 */ 58 links: { 59 /** AOL Instant Messenger link */ 60 AIM: "aim:goim?screenname=", 61 /** MSN Messenger link */ 62 MSN: "msnim:chat?contact=", 63 /** Yahoo Me3ssenger link */ 64 YAHOO: "ymsgr:sendim?", 65 /** Skype link */ 66 SKYPE: "skype:", 67 /** Skype chat link */ 68 SKYPES: "?chat", 69 /** Jabber link */ 70 JABBER: "xmpp:", 71 /** XMPP link */ 72 XMPP: "xmpp:", 73 /** Google Talk link */ 74 GOOGLE_TALK: "gtalk:chat?jid=" 75 }, 76 /** 77 * Called when the overlay is loaded and overrides some methods to add 78 * gContactSync fields. 79 */ 80 initialize: function ABOverlay_initialize() { 81 // determine if this is before or after Bug 413260 landed 82 var card = Components.classes["@mozilla.org/addressbook/cardproperty;1"] 83 .createInstance(Components.interfaces.nsIAbCard); 84 this.mBug413260 = card.getProperty ? true : false; 85 86 com.gContactSync.originalOnLoadCardView = OnLoadCardView; 87 OnLoadCardView = this.myOnLoadCardView; 88 if (com.gContactSync.Preferences.mSyncPrefs.enableSyncBtn.value) 89 this.setupButton(); // insert the Sync button 90 // add the extra attributes as tree columns to show and 91 this.addTreeCols(); // sort by in the results pane if this is after 413260 92 // override the onDrop method of abDirTreeObserver 93 // so when a card is copied the extra attributes are copied with it 94 if (com.gContactSync.Preferences.mSyncPrefs.overrideCopy.value) 95 abDirTreeObserver.onDrop = com.gContactSync.myOnDrop; 96 // override the display card view pane 97 com.gContactSync.originalDisplayCardViewPane = DisplayCardViewPane; 98 DisplayCardViewPane = this.myDisplayCardViewPane; 99 // Add a reset menuitem to the directory tree context menu 100 if (com.gContactSync.Preferences.mSyncPrefs.addReset.value) { 101 this.addResetContext(); 102 } 103 // override the ab results tree function 104 //com.gContactSync.originalSetAbView = SetAbView; 105 //SetAbView = com.gContactSync.SetAbView; 106 // Fix the style for description elements accidentally set in the 107 // Duplicate Contacts Manager extension 108 // https://www.mozdev.org/bugs/show_bug.cgi?id=21883 109 if (com.gContactSync.Preferences.mSyncPrefs.fixDupContactManagerCSS.value) 110 this.fixDescriptionStyle(); 111 // load the card view (required by seamonkey) 112 if (document.getElementById("ab-menubar")) 113 this.myOnLoadCardView(); 114 }, 115 /** 116 * Adds treecol elements to the address book results tree that shows cards in 117 * the currently selected directory. These treecols allow the user to show 118 * and sort by extra attributes that are added by this extension. This will 119 * only work after Bug 413260 landed, so in Thunderbird 3.0b1pre and after. 120 */ 121 addTreeCols: function ABOverlay_addTreeCols() { 122 // get the treecols XUL element 123 var treeCols = document.getElementById("abResultsTreeCols"); 124 if (!treeCols || !treeCols.appendChild) 125 return; 126 // if Bug 413260 isn't applied in this version of TB, or if the pref was 127 // changed to false, then stop here 128 if (!this.mBug413260 || !com.gContactSync.Preferences.mSyncPrefs.newColLabels.value) 129 return; 130 // get the added attributes 131 var ids = com.gContactSync.ContactConverter.getExtraSyncAttributes(false, false), 132 id, splitter, treeCol; 133 // iterate through every added attribute and add a treecol for it unless 134 // it is a postal address 135 for (i = 0, length = ids.length; i < length; i++) { 136 id = ids[i]; 137 if (id.indexOf("Type") !== -1) 138 continue; // skip addresses and Types 139 // make and add the splitter first 140 splitter = document.createElement("splitter"); 141 splitter.setAttribute("class", "tree-splitter"); 142 treeCols.appendChild(splitter); 143 // make the new treecol 144 treeCol = document.createElement("treecol"); 145 // then set it up with the ID and other attributes 146 treeCol.setAttribute("id", id); 147 treeCol.setAttribute("class", "sortDirectionIndicator"); 148 treeCol.setAttribute("hidden", "true"); 149 treeCol.setAttribute("persist", "hidden ordinal width sortDirection"); 150 treeCol.setAttribute("flex", "1"); 151 treeCol.setAttribute("label", com.gContactSync.StringBundle.getStr(id)); 152 // append it to the treecols element 153 treeCols.appendChild(treeCol); 154 } 155 156 // Fix/rename phone number columns if the phoneColLabels is on AND phone 157 // number types have been added. 158 if (com.gContactSync.Preferences.mSyncPrefs.phoneColLabels.value && 159 com.gContactSync.Preferences.mSyncPrefs.phoneTypes.value) { 160 // fix/rename the existing phone numbers 161 var arr = ["WorkPhone", "HomePhone", "FaxNumber", "CellularNumber", 162 "PagerNumber", "HomeFaxNumber", "OtherNumber"]; 163 // the strings from the string bundle 164 var arr2 = ["firstNumber", "secondNumber", "thirdNumber", "fourthNumber", 165 "fifthNumber", "sixthNumber", "seventhNumber"]; 166 var elem; 167 for (var i = 0; i < arr.length; i++) { 168 elem = document.getElementById(arr[i]); 169 if (!elem) { 170 continue; 171 } 172 // remove it 173 treeCols.removeChild(elem); 174 elem.setAttribute("label", com.gContactSync.StringBundle.getStr(arr2[i])); 175 // and then add it to the end of the treecols element 176 treeCols.appendChild(elem); 177 } 178 } 179 }, 180 /** 181 * Sets up the Sync button to go between the Write and Delete buttons and adds 182 * a separator between Sync and Delete. 183 * @returns {boolean} True if the button was added manually. 184 */ 185 setupButton: function ABOverlay_setupButton() { 186 try { 187 com.gContactSync.LOGGER.VERBOSE_LOG("Trying to add button"); 188 // get the toolbar with the buttons 189 var toolbar = document.getElementById("abToolbar"); // seamonkey 190 if (!toolbar) { 191 com.gContactSync.LOGGER.VERBOSE_LOG("Didn't find the toolbar"); 192 return false; 193 } 194 // setup the separators 195 var separator = document.createElement("toolbarseparator"); 196 var separator2 = document.createElement("toolbarseparator"); 197 // setup the button 198 var button = document.createElement("toolbarbutton"); 199 button.setAttribute("class", "gContactSync-Button toolbarbutton-1" + 200 " chromeclass-toolbar-additional"); 201 button.setAttribute("id", "button-sync"); 202 button.setAttribute("label", 203 com.gContactSync.StringBundle.getStr("syncButton")); 204 button.setAttribute("oncommand", "com.gContactSync.Sync.begin();"); 205 button.setAttribute("tooltiptext", 206 com.gContactSync.StringBundle.getStr("syncTooltip")); 207 button.setAttribute("insertbefore", "new-separator"); 208 209 var deleteButton = document.getElementById("button-delete"); 210 var writeButton = document.getElementById("button-newmessage"); 211 var addedButton = false; 212 // first, try to insert it after the delete button 213 if (deleteButton) { 214 try { 215 // insert the separator before the Delete button 216 toolbar.insertBefore(separator, deleteButton); 217 // insert the button before the separator 218 toolbar.insertBefore(button, separator); 219 com.gContactSync.LOGGER.VERBOSE_LOG("Added the button before the delete button"); 220 addedButton = true; 221 // insert the second separator before the button if necessary 222 if (button.previousSibling && button.previousSibling.nodeName != "toolbarseparator") { 223 toolbar.insertBefore(separator2, button); 224 com.gContactSync.LOGGER.VERBOSE_LOG("Also added a separator before the button"); 225 } 226 } 227 catch (e) { 228 com.gContactSync.LOGGER.LOG_WARNING("Couldn't setup the sync button before the delete button", e); 229 } 230 } 231 // if that doesn't work, try after the write button 232 if (writeButton && !addedButton) { 233 try { 234 // insert the separator before the Write button 235 toolbar.insertBefore(separator, writeButton); 236 // insert the button before the separator 237 toolbar.insertBefore(button, separator); 238 com.gContactSync.LOGGER.VERBOSE_LOG("Added the button before the compose button"); 239 com.gContactSync.LOGGER.VERBOSE_LOG("Added a separator after the button"); 240 addedButton = true; 241 // insert the second separator before the button if necessary 242 if (button.previousSibling && button.previousSibling.nodeName != "toolbarseparator") { 243 toolbar.insertBefore(separator2, button); 244 com.gContactSync.LOGGER.VERBOSE_LOG("Added a separator before the button"); 245 } 246 } 247 catch (e) { 248 com.gContactSync.LOGGER.LOG_WARNING("Couldn't setup the sync button before the write button", e); 249 } 250 } 251 // if all else fails try to append the button at the end of the toolbar 252 if (!addedButton) { 253 com.gContactSync.LOGGER.VERBOSE_LOG("Attempting to append the toolbar button"); 254 toolbar.appendChild(separator); 255 toolbar.appendChild(button); 256 } 257 if (com.gContactSync.Preferences.mSyncPrefs.forceBtnImage.value) { 258 com.gContactSync.LOGGER.VERBOSE_LOG("Forcing the listStyleImage for the button"); 259 document.getElementById("button-sync").style.listStyleImage = 260 "url('chrome://gcontactsync/skin/logo_main_24.png')"; 261 } 262 com.gContactSync.LOGGER.VERBOSE_LOG("Finished adding button\n"); 263 return true; 264 } 265 catch(e) { 266 com.gContactSync.LOGGER.LOG_WARNING("Couldn't setup the sync button", e); 267 } 268 return false; 269 }, 270 /** 271 * Modifies the SetAbView function. Unused 272 */ 273 // NOTE - this function can break search and more if not overridden properly 274 mySetAbView: function ABOverlay_mySetAbView(aURI, aSearchView, aSortCol, aSortDir) { 275 // call the original 276 com.gContactSync.originalSetAbView.apply(this, arguments); 277 // TODO fix this 278 /* 279 var children = gAbResultsTree.getElementsByAttribute("ondraggesture", "nsDragAndDrop.startDrag(event, abResultsPaneObserver);"); 280 var treeChildren = children[0]; 281 var str = ""; 282 for (var i = 0; i < children[0].children.length; i++) { 283 str += children[0].children[i] + "\n"; 284 } 285 com.gContactSync.alert(str + "\n" + children[0].children); 286 */ 287 /*for (var i in gAbResultsTree.children[0]) 288 str += i + "\n"; 289 str += "1:\n"; 290 for (var i in gAbResultsTree.children[1]) 291 str += i + "\n"; 292 com.gContactSync.alert(str);*/ 293 // now find and hide any dummy e-mail addresses 294 }, 295 /** 296 * Updates the Card View pane boxes and headers for whether or not they should 297 * be visible based on additional attributes added by gContactSync. 298 * Links the third and fourth e-mail address as well as the "other" address. 299 * Should be set to override the DisplayCardViewPane function in 300 * abCardViewOverlay.js. Requires that the original function should be set as 301 * the com.gContactSync.originalDisplayCardViewPane variable. 302 * @param aCard {nsIAbCard} The card being viewed. 303 */ 304 myDisplayCardViewPane: function ABOverlay_myDisplayCardViewPane(aCard) { 305 // call the original first 306 com.gContactSync.originalDisplayCardViewPane.apply(this, arguments); 307 if (aCard.isMailList) { 308 // collapse all the attributes added 309 com.gContactSync.ABOverlay.hideNodes(com.gContactSync.ContactConverter.getExtraSyncAttributes(false, true)); 310 try { 311 // then collapse the e-mail boxes 312 cvData.cvThirdEmailBox.collapsed = true; 313 cvData.cvFourthEmailBox.collapsed = true; 314 } catch(e) {} 315 return; // and quit, nothing was added for mail lists 316 } 317 try { 318 var contact; 319 320 // If able to get the selected directory then show the lists this contact 321 // is in 322 if (GetSelectedDirectory === undefined || !cvData.cvLists) { 323 contact = new com.gContactSync.TBContact(aCard, null); 324 } else if (GetSelectedDirectory()) { 325 326 var ab = (com.gContactSync.GAbManager.getAllAddressBooks(2))[GetSelectedDirectory()]; 327 328 if (!ab) { 329 // It is a mailing list, truncate everything from the last "/" to 330 // get the AB's URI. 331 ab = (com.gContactSync.GAbManager.getAllAddressBooks(2)) 332 [GetSelectedDirectory().substring(0,GetSelectedDirectory().lastIndexOf("/"))]; 333 } 334 335 if (!ab) { 336 cvData.cvLists.parentNode.collapsed = true; 337 contact = new com.gContactSync.TBContact(aCard, null); 338 } else { 339 cvData.cvLists.parentNode.collapsed = false; 340 contact = new com.gContactSync.TBContact(aCard, ab); 341 342 // Get all lists in this AB, but do NOT get it's contacts yet 343 var lists = ab.getAllLists(true); 344 var listsWithContact = []; 345 346 // Iterate through each list in this AB 347 // If the list is "broken" (enumeration through it's contacts fails) 348 // then just ignore the error and move on. 349 for (var i in lists) { 350 lists[i].setIgnoreIfBroken(true); 351 lists[i].getAllContacts(); 352 if (lists[i].hasContact(contact)) { 353 listsWithContact.push(lists[i].getName()); 354 } 355 lists[i].setIgnoreIfBroken(false); 356 } 357 358 cvData.cvLists.data = listsWithContact.join(" | "); 359 } 360 } 361 com.gContactSync.ABOverlay.showNodes(com.gContactSync.ContactConverter.getExtraSyncAttributes(false, true)); 362 var primaryEmail = com.gContactSync.GAbManager.getCardValue(aCard, 363 com.gContactSync.dummyEmailName); 364 // if the primary e-mail address is the dummy address, hide it 365 if (com.gContactSync.isDummyEmail(primaryEmail)) { 366 // TODO recalculate if the contact info box must be collapsed too 367 switch (com.gContactSync.dummyEmailName) { 368 case "PrimaryEmail" : 369 cvData.cvEmail1Box.collapsed = true; 370 break; 371 case "SecondEmail" : 372 cvData.cvEmail2Box.collapsed = true; 373 break; 374 default: 375 com.gContactSync.alertError("Error - invalid dummy email name"); 376 } 377 } 378 cvData.cvThirdEmailBox.collapsed = false; 379 cvData.cvFourthEmailBox.collapsed = false; 380 // Contact section (ThirdEmail, FourthEmail, TalkScreenName, MSNScreenName, 381 // JabberScreenName, YahooScreenName, ICQScreenName) 382 var visible = !cvData.cvbContact.getAttribute("collapsed"); 383 // don't show the Third and Fourth e-mail addresses in Postbox 384 if (!contact.mPostbox) { 385 var thirdEmail = contact.getValue("ThirdEmail"); 386 var fourthEmail = contact.getValue("FourthEmail"); 387 visible = HandleLink(cvData.cvThirdEmail, com.gContactSync.StringBundle.getStr("ThirdEmail"), 388 thirdEmail, cvData.cvThirdEmailBox, "mailto:" + 389 thirdEmail) || visible; 390 // Workaround for a bug where the collapsed attributes set here don't 391 // seem to get applied 392 document.getElementById(cvData.cvThirdEmailBox.id).collapsed = cvData.cvThirdEmailBox.collapsed; 393 visible = HandleLink(cvData.cvFourthEmail, com.gContactSync.StringBundle.getStr("FourthEmail"), 394 fourthEmail, cvData.cvFourthEmailBox, "mailto:" + 395 fourthEmail) || visible; 396 } 397 398 visible = com.gContactSync.ABOverlay.getVisible(aCard, ["TalkScreenName", 399 "JabberScreenName", 400 "YahooScreenName", 401 "MSNScreenName", 402 "ICQScreenName"], 403 visible, true); 404 cvSetVisible(cvData.cvhContact, visible); 405 cvSetVisible(cvData.cvbContact, visible); 406 // Other section (OtherAddress) 407 var visible = !cvData.cvhOther.getAttribute("collapsed"); 408 visible = com.gContactSync.ABOverlay.getVisible(aCard, ["OtherAddress"], visible); 409 cvSetVisible(cvData.cvhOther, visible); 410 cvSetVisible(cvData.cvbOther, visible); 411 // setup the OtherAddress MapIt button 412 if (cvData.cvOtherAddress && cvData.cvOtherAddress.childNodes[0] && 413 cvData.cvOtherAddress.childNodes[0].nodeValue) { 414 var baseUrl = "http://maps.google.com/maps?q="; 415 var address = cvData.cvOtherAddress.childNodes[0].nodeValue; 416 // remove the label 417 var index = address.indexOf(":") 418 if (index != -1 && address.length > index + 2) 419 address = address.substring(address.indexOf(":") + 2); 420 cvData.cvOtherMapIt.setAttribute("url", baseUrl + encodeURIComponent(address)); 421 cvSetVisible(cvData.cvbOtherMapItBox, true); 422 } 423 else { 424 cvData.cvOtherMapIt.setAttribute("url", ""); 425 cvSetVisible(cvData.cvbOtherMapItBox, false); 426 } 427 // setup the OtherAddress MapIt button 428 if (cvData.cvOtherAddress && cvData.cvOtherAddress.childNodes[0] && 429 cvData.cvOtherAddress.childNodes[0].nodeValue) { 430 var baseUrl = "http://maps.google.com/maps?q="; 431 var address = cvData.cvOtherAddress.childNodes[0].nodeValue; 432 // remove the label 433 var index = address.indexOf(":"); 434 if (index != -1 && address.length > index + 2) 435 address = address.substring(address.indexOf(":") + 2); 436 cvData.cvOtherMapIt.setAttribute("url", baseUrl + encodeURIComponent(address)); 437 cvSetVisible(cvData.cvbOtherMapItBox, true); 438 } 439 else { 440 cvData.cvOtherMapIt.setAttribute("url", ""); 441 cvSetVisible(cvData.cvbOtherMapItBox, false); 442 } 443 // Home Section (FullHomeAddress) 444 var visible = !cvData.cvhHome.getAttribute("collapsed"); 445 visible = com.gContactSync.ABOverlay.getVisible(aCard, ["FullHomeAddress"], visible); 446 cvSetVisible(cvData.cvhHome, visible); 447 cvSetVisible(cvData.cvbHome, visible); 448 // setup the HomeAddress MapIt button 449 if (cvData.cvFullHomeAddress && cvData.cvFullHomeAddress.childNodes[0] && 450 cvData.cvFullHomeAddress.childNodes[0].nodeValue) { 451 var baseUrl = "http://maps.google.com/maps?q="; 452 var address = cvData.cvFullHomeAddress.childNodes[0].nodeValue; 453 // remove the label 454 var index = address.indexOf(":") 455 if (index != -1 && address.length > index + 2) 456 address = address.substring(address.indexOf(":") + 2); 457 cvData.cvFullHomeMapIt.setAttribute("url", baseUrl + encodeURIComponent(address)); 458 cvSetVisible(cvData.cvbFullHomeMapItBox, true); 459 // hide the old home address... 460 com.gContactSync.ABOverlay.collapseAddress("Home"); 461 } 462 else { 463 cvData.cvFullHomeMapIt.setAttribute("url", ""); 464 cvSetVisible(cvData.cvbFullHomeMapItBox, false); 465 } 466 // Work Section (FullWorkAddress) 467 var visible = !cvData.cvhWork.getAttribute("collapsed"); 468 visible = com.gContactSync.ABOverlay.getVisible(aCard, ["FullWorkAddress"], visible); 469 cvSetVisible(cvData.cvhWork, visible); 470 cvSetVisible(cvData.cvbWork, visible); 471 // setup the WorkAddress MapIt button 472 if (cvData.cvFullWorkAddress && cvData.cvFullWorkAddress.childNodes[0] && 473 cvData.cvFullWorkAddress.childNodes[0].nodeValue) { 474 var baseUrl = "http://maps.google.com/maps?q="; 475 var address = cvData.cvFullWorkAddress.childNodes[0].nodeValue; 476 // remove the label 477 var index = address.indexOf(":"); 478 if (index != -1 && address.length > index + 2) 479 address = address.substring(address.indexOf(":") + 2); 480 cvData.cvFullWorkMapIt.setAttribute("url", baseUrl + encodeURIComponent(address)); 481 cvSetVisible(cvData.cvbFullWorkMapItBox, true); 482 // hide the old Work address... 483 com.gContactSync.ABOverlay.collapseAddress("Work"); 484 } 485 else { 486 cvData.cvFullWorkMapIt.setAttribute("url", ""); 487 cvSetVisible(cvData.cvbFullWorkMapItBox, false); 488 } 489 // Other section (relations) 490 var visible = !cvData.cvhOther.getAttribute("collapsed"); 491 // Relation fields 492 visible = com.gContactSync.ABOverlay.getVisible(aCard, ["Relation0", 493 "Relation1", 494 "Relation2", 495 "Relation3"], 496 visible, true); 497 cvSetVisible(cvData.cvhOther, visible); 498 cvSetVisible(cvData.cvbOther, visible); 499 // Phone section (add OtherNumber and HomeFaxNumber) 500 // first, add the existing nodes to cvData under a name that actually 501 // matches the attribute 502 cvData.cvWorkPhone = cvData.cvPhWork; 503 cvData.cvHomePhone = cvData.cvPhHome; 504 cvData.cvFaxNumber = cvData.cvPhFax; 505 cvData.cvCellularNumber = cvData.cvPhCellular; 506 cvData.cvPagerNumber = cvData.cvPhPager; 507 // then set the value and labels for the new and old phone nodes 508 var visible = !cvData.cvhPhone.getAttribute("collapsed"); 509 visible = com.gContactSync.ABOverlay.getVisible(aCard, ["WorkPhone", "HomePhone", "FaxNumber", 510 "CellularNumber", "PagerNumber", 511 "OtherNumber", "HomeFaxNumber"], 512 visible, true); 513 cvSetVisible(cvData.cvhPhone, visible); 514 cvSetVisible(cvData.cvbPhone, visible); 515 } catch(e) { 516 com.gContactSync.alertError("Error while modifying view pane: " + e); 517 com.gContactSync.LOGGER.LOG_WARNING("Error while modifying the view pane.", e); 518 } 519 }, 520 /** 521 * Collapses (hides) the old components of an address: Address Line 1 and 2, 522 * the City, State Zip line, and the Country of the given type (Home or Work). 523 * @param aPrefix {string} The type of address. Must be 'Home' or 'Work'. 524 */ 525 collapseAddress: function ABOverlay_collapseAddress(aPrefix) { 526 if (!aPrefix || (aPrefix != "Home" && aPrefix != "Work")) 527 return; 528 var arr = ["Address", "Address2", "CityStZip", "Country"]; 529 for (var i = 0, length = arr.length; i < length; i++) { 530 var id = "cv" + aPrefix + arr[i]; 531 var elem = document.getElementById(id); 532 if (elem && elem.setAttribute) 533 elem.setAttribute("collapsed", true); 534 } 535 var mapItBox = document.getElementById("cvb" + aPrefix + "MapItBox"); 536 if (mapItBox && mapItBox.setAttribute) 537 mapItBox.setAttribute("collapsed", true); 538 }, 539 /** 540 * Hides all of the nodes based on the array. The node must be a propery of 541 * cvData with the same name as the element in aArray prefixed with a 'cv'. 542 * For example, to hide cvData.cvHomeAddress the element would be 543 * 'HomeAddress'. 544 * @param {array} aArray An array of names as described above. 545 */ 546 hideNodes: function ABOverlay_hideNodes(aArray) { 547 for (var i = 0, length = aArray.length; i < length; i++) { 548 if (aArray[i].indexOf("Type") != -1) 549 continue; 550 try { 551 cvSetVisible(cvData["cv" + aArray[i]], false); 552 } 553 catch (e) { 554 com.gContactSync.LOGGER.LOG_WARNING("Error while hiding node '" + aArray[i] + "'", e); 555 } 556 } 557 }, 558 /** 559 * Shows all of the nodes based on the array. The node must be a propery of 560 * cvData with the same name as the element in aArray prefixed with a 'cv'. 561 * For example, to show cvData.cvHomeAddress the element would be 562 * 'HomeAddress'. 563 * @param aArray {array} An array of names as described above. 564 */ 565 showNodes: function ABOverlay_showNodes(aArray) { 566 for (var i = 0, length = aArray.length; i < length; i++) { 567 if (aArray[i].indexOf("Type") != -1) 568 continue; 569 try { 570 cvSetVisible(cvData["cv" + aArray[i]], true); 571 } 572 catch (e) { 573 com.gContactSync.LOGGER.LOG_WARNING("Error while showing node '" + aArray[i] + "'", e); 574 } 575 } 576 }, 577 /** 578 * A helper method for myDisplayCardViewPane that iterates through an array of 579 * attributes and returns true if at least one of them is present in the given 580 * card. 581 * @param aCard {nsIAbCard} The card whose attributes are checked. 582 * @param aArray {array} The array of attributes to check for in 583 * the card. 584 * @param aVisible {boolean} Optional. True if the element was 585 * previously visible. 586 * @param aUseTypeLabel {boolean} Optional. True if the labels should be 587 * the type of the attribute instead of the 588 * attribute's name. 589 * @returns {boolean} True if at least one attribute in aArray is present in aCard. 590 */ 591 getVisible: function ABOverlay_getVisible(aCard, aArray, aVisible, aUseTypeLabel) { 592 var visible = aVisible; 593 // return true if the card has the current attribute 594 for (var i = 0; i < aArray.length; i++) { 595 var attr = aArray[i]; 596 var value = com.gContactSync.GAbManager.getCardValue(aCard, attr); 597 // get the name of the string to find in the bundle 598 var label = aUseTypeLabel ? com.gContactSync.GAbManager.getCardValue(aCard, attr + "Type") 599 : attr; 600 // get the actual string 601 // if the label is null (ie aUseTypeLabel was true, but there wasn't a type) 602 // then use the attribute's string as a default value 603 var str = label && label != "" ? com.gContactSync.StringBundle.getStr(label) 604 : com.gContactSync.StringBundle.getStr(attr); 605 var prefix = this.links[label]; 606 // Make this a link if there is a prefix (aim:goim?...), the pref is set, 607 // and there is a box for this data 608 if (prefix && com.gContactSync.Preferences.mSyncPrefs.enableImUrls.value && cvData["cv" + attr + "Box"]) { 609 var suffix = this.links[label + "S"] ? this.links[label + "S"] : ""; 610 visible = HandleLink(cvData["cv" + attr], str, value, 611 cvData["cv" + attr + "Box"], prefix + 612 value + suffix) || visible; 613 } 614 else 615 visible = cvSetNodeWithLabel(cvData["cv" + attr], str, value) || visible; 616 } 617 return visible; 618 }, 619 /** 620 * Sets up a few nodes and labels in addition to what the OnLoadCardView 621 * function does in abCardViewOverlay.js. Should be run when the Overlay is 622 * loaded. 623 */ 624 myOnLoadCardView: function ABOverlay_myOnLoadCardView() { 625 if (!com.gContactSync.originalOnLoadCardView) 626 return; 627 com.gContactSync.originalOnLoadCardView.apply(this, arguments); 628 629 // add the <description> elements 630 var vbox = document.getElementById("cvbContact"); 631 // setup the third and fourth e-mail addresses 632 var xhtml = "http://www.w3.org/1999/xhtml"; 633 cvData.cvThirdEmailBox = com.gContactSync.ABOverlay.makeDescElement("ThirdEmailBox", 634 "CardViewLink"); 635 cvData.cvThirdEmail = document.createElementNS(xhtml, "html:a"); 636 cvData.cvThirdEmail.setAttribute("id", "ThirdEmail"); 637 cvData.cvThirdEmailBox.appendChild(cvData.cvThirdEmail); 638 cvData.cvFourthEmailBox = com.gContactSync.ABOverlay.makeDescElement("FourthEmailBox", 639 "CardViewLink"); 640 cvData.cvFourthEmail = document.createElementNS(xhtml, "html:a"); 641 cvData.cvFourthEmail.setAttribute("id", "FourthEmail"); 642 cvData.cvFourthEmailBox.appendChild(cvData.cvFourthEmail); 643 vbox.insertBefore(cvData.cvFourthEmailBox, document.getElementById("cvScreennameBox")); 644 vbox.insertBefore(cvData.cvThirdEmailBox, cvData.cvFourthEmailBox); 645 646 // the screennames 647 if (com.gContactSync.Preferences.mSyncPrefs.enableImUrls.value) { 648 cvData.cvTalkScreenNameBox = com.gContactSync.ABOverlay.makeDescElement("TalkScreenNameBox", 649 "CardViewLink"); 650 cvData.cvTalkScreenName = document.createElementNS(xhtml, "html:a"); 651 cvData.cvTalkScreenName.setAttribute("id", "TalkScreenName"); 652 cvData.cvTalkScreenNameBox.appendChild(cvData.cvTalkScreenName); 653 cvData.cvICQScreenNameBox = com.gContactSync.ABOverlay.makeDescElement("ICQScreenNameBox", 654 "CardViewLink"); 655 cvData.cvICQScreenName = document.createElementNS(xhtml, "html:a"); 656 cvData.cvICQScreenName.setAttribute("id", "ICQScreenName"); 657 cvData.cvICQScreenNameBox.appendChild(cvData.cvICQScreenName); 658 cvData.cvYahooScreenNameBox = com.gContactSync.ABOverlay.makeDescElement("YahooScreenNameBox", 659 "CardViewLink"); 660 cvData.cvYahooScreenName = document.createElementNS(xhtml, "html:a"); 661 cvData.cvYahooScreenName.setAttribute("id", "YahooScreenName"); 662 cvData.cvYahooScreenNameBox.appendChild(cvData.cvYahooScreenName); 663 cvData.cvMSNScreenNameBox = com.gContactSync.ABOverlay.makeDescElement("MSNScreenNameBox", 664 "CardViewLink"); 665 cvData.cvMSNScreenName = document.createElementNS(xhtml, "html:a"); 666 cvData.cvMSNScreenName.setAttribute("id", "MSNScreenName"); 667 cvData.cvMSNScreenNameBox.appendChild(cvData.cvMSNScreenName); 668 cvData.cvJabberScreenNameBox = com.gContactSync.ABOverlay.makeDescElement("JabberScreenNameBox", 669 "CardViewLink"); 670 cvData.cvJabberScreenName = document.createElementNS(xhtml, "html:a"); 671 cvData.cvJabberScreenName.setAttribute("id", "JabberScreenName"); 672 cvData.cvJabberScreenNameBox.appendChild(cvData.cvJabberScreenName); 673 674 vbox.appendChild(cvData.cvTalkScreenNameBox); 675 vbox.appendChild(cvData.cvICQScreenNameBox); 676 vbox.appendChild(cvData.cvMSNScreenNameBox); 677 vbox.appendChild(cvData.cvYahooScreenNameBox); 678 vbox.appendChild(cvData.cvJabberScreenNameBox); 679 } 680 else { 681 cvData.cvTalkScreenName = com.gContactSync.ABOverlay.makeDescElement("TalkScreenName", "CardViewText"); 682 cvData.cvICQScreenName = com.gContactSync.ABOverlay.makeDescElement("ICQScreenName", "CardViewText"); 683 cvData.cvYahooScreenName = com.gContactSync.ABOverlay.makeDescElement("YahooScreenName", "CardViewText"); 684 cvData.cvMSNScreenName = com.gContactSync.ABOverlay.makeDescElement("MSNScreenName", "CardViewText"); 685 cvData.cvJabberScreenName = com.gContactSync.ABOverlay.makeDescElement("JabberScreenName", "CardViewText"); 686 vbox.appendChild(cvData.cvTalkScreenName); 687 vbox.appendChild(cvData.cvICQScreenName); 688 vbox.appendChild(cvData.cvMSNScreenName); 689 vbox.appendChild(cvData.cvYahooScreenName); 690 vbox.appendChild(cvData.cvJabberScreenName); 691 } 692 // Other Address 693 vbox = document.getElementById("cvbOther"); 694 var otherHbox = document.createElement("hbox"); 695 var otherVbox = document.createElement("vbox"); 696 otherVbox.setAttribute("flex", "1"); 697 cvData.cvOtherAddress = com.gContactSync.ABOverlay.makeDescElement("OtherAddress", "CardViewText"); 698 if (Components.classes["@mozilla.org/abmanager;1"]) // TB 3 - style should be pre-wrap 699 cvData.cvOtherAddress.setAttribute("style", "white-space: pre-wrap;"); 700 else // TB 2 - the style should be -moz-pre-wrap 701 cvData.cvOtherAddress.setAttribute("style", "white-space: -moz-pre-wrap;"); 702 // setup the MapIt box 703 cvData.cvbOtherMapItBox = document.createElement("vbox"); 704 cvData.cvbOtherMapItBox.setAttribute("id", "cvbOtherMapItBox"); 705 cvData.cvbOtherMapItBox.setAttribute("pack", "end"); 706 cvData.cvOtherMapIt = document.createElement("button"); 707 cvData.cvOtherMapIt.setAttribute("label", 708 com.gContactSync.StringBundle.getStr("getMap")); 709 cvData.cvOtherMapIt.setAttribute("url", ""); 710 cvData.cvOtherMapIt.setAttribute("oncommand", "MapIt('cvOtherMapIt');"); 711 cvData.cvOtherMapIt.setAttribute("tooltip", 712 com.gContactSync.StringBundle.getStr("getMapTooltip")); 713 cvData.cvOtherMapIt.setAttribute("id", "cvOtherMapIt"); 714 otherVbox.appendChild(cvData.cvOtherAddress); 715 cvData.cvbOtherMapItBox.appendChild(cvData.cvOtherMapIt); 716 otherHbox.appendChild(otherVbox); 717 otherHbox.appendChild(cvData.cvbOtherMapItBox); 718 vbox.appendChild(otherHbox); 719 // FullHomeAddress 720 vbox = document.getElementById("cvbHome"); 721 var FullHomeHbox = document.createElement("hbox"); 722 var FullHomeVbox = document.createElement("vbox"); 723 FullHomeVbox.setAttribute("flex", "1"); 724 cvData.cvFullHomeAddress = com.gContactSync.ABOverlay.makeDescElement("FullHomeAddress", "CardViewText"); 725 if (Components.classes["@mozilla.org/abmanager;1"]) // TB 3 - style should be pre-wrap 726 cvData.cvFullHomeAddress.setAttribute("style", "white-space: pre-wrap;"); 727 else // TB 2 - the style should be -moz-pre-wrap 728 cvData.cvFullHomeAddress.setAttribute("style", "white-space: -moz-pre-wrap;"); 729 // setup the MapIt box 730 cvData.cvbFullHomeMapItBox = document.createElement("vbox"); 731 cvData.cvbFullHomeMapItBox.setAttribute("id", "cvbFullHomeMapItBox"); 732 cvData.cvbFullHomeMapItBox.setAttribute("pack", "end"); 733 cvData.cvFullHomeMapIt = document.createElement("button"); 734 cvData.cvFullHomeMapIt.setAttribute("label", 735 com.gContactSync.StringBundle.getStr("getMap")); 736 cvData.cvFullHomeMapIt.setAttribute("url", ""); 737 cvData.cvFullHomeMapIt.setAttribute("oncommand", "MapIt('cvFullHomeMapIt');"); 738 cvData.cvFullHomeMapIt.setAttribute("tooltip", 739 com.gContactSync.StringBundle.getStr("getMapTooltip")); 740 cvData.cvFullHomeMapIt.setAttribute("id", "cvFullHomeMapIt"); 741 FullHomeVbox.appendChild(cvData.cvFullHomeAddress); 742 cvData.cvbFullHomeMapItBox.appendChild(cvData.cvFullHomeMapIt); 743 FullHomeHbox.appendChild(FullHomeVbox); 744 FullHomeHbox.appendChild(cvData.cvbFullHomeMapItBox); 745 var homeWebPageBox = document.getElementById("cvHomeWebPageBox"); 746 if (homeWebPageBox) 747 vbox.insertBefore(FullHomeHbox, homeWebPageBox); 748 else 749 vbox.appendChild(FullHomeHbox); 750 // FullWorkAddress 751 vbox = document.getElementById("cvbWork"); 752 var FullWorkHbox = document.createElement("hbox"); 753 var FullWorkVbox = document.createElement("vbox"); 754 FullWorkVbox.setAttribute("flex", "1"); 755 cvData.cvFullWorkAddress = com.gContactSync.ABOverlay.makeDescElement("FullWorkAddress", "CardViewText"); 756 if (Components.classes["@mozilla.org/abmanager;1"]) // TB 3 - style should be pre-wrap 757 cvData.cvFullWorkAddress.setAttribute("style", "white-space: pre-wrap;"); 758 else // TB 2 - the style should be -moz-pre-wrap 759 cvData.cvFullWorkAddress.setAttribute("style", "white-space: -moz-pre-wrap;"); 760 // setup the MapIt box 761 cvData.cvbFullWorkMapItBox = document.createElement("vbox"); 762 cvData.cvbFullWorkMapItBox.setAttribute("id", "cvbFullWorkMapItBox"); 763 cvData.cvbFullWorkMapItBox.setAttribute("pack", "end"); 764 cvData.cvFullWorkMapIt = document.createElement("button"); 765 cvData.cvFullWorkMapIt.setAttribute("label", com.gContactSync.StringBundle.getStr("getMap")); 766 cvData.cvFullWorkMapIt.setAttribute("url", ""); 767 cvData.cvFullWorkMapIt.setAttribute("oncommand", "MapIt('cvFullWorkMapIt');"); 768 cvData.cvFullWorkMapIt.setAttribute("tooltip", com.gContactSync.StringBundle.getStr("getMapTooltip")); 769 cvData.cvFullWorkMapIt.setAttribute("id", "cvFullWorkMapIt"); 770 FullWorkVbox.appendChild(cvData.cvFullWorkAddress); 771 cvData.cvbFullWorkMapItBox.appendChild(cvData.cvFullWorkMapIt); 772 FullWorkHbox.appendChild(FullWorkVbox); 773 FullWorkHbox.appendChild(cvData.cvbFullWorkMapItBox); 774 var WorkWebPageBox = document.getElementById("cvWorkWebPageBox"); 775 if (WorkWebPageBox) 776 vbox.insertBefore(FullWorkHbox, WorkWebPageBox); 777 else 778 vbox.appendChild(FullWorkHbox); 779 780 // Work section 781 cvData.cvJobDescription = com.gContactSync.ABOverlay.makeDescElement("JobDescription", "CardViewText"); 782 cvData.cvCompanySymbol = com.gContactSync.ABOverlay.makeDescElement("CompanySymbol", "CardViewText"); 783 vbox = document.getElementById("cvbWork"); 784 // Add the job description after the job title 785 vbox.insertBefore(cvData.cvJobDescription, cvData.cvJobTitle.nextSibling); 786 // Add the company symbol after the company name 787 vbox.insertBefore(cvData.cvCompanySymbol, cvData.cvCompany.nextSibling); 788 789 // Other section 790 vbox = document.getElementById("cvbOther"); 791 var otherHbox = document.createElement("hbox"); 792 var otherVbox = document.createElement("vbox"); 793 otherVbox.setAttribute("flex", "1"); 794 // Relation fields) 795 for (var i = 0; i < 4; i++) { 796 cvData["cvRelation" + i] = com.gContactSync.ABOverlay.makeDescElement("Relation" + i, "CardViewText"); 797 otherVbox.appendChild(cvData["cvRelation" + i]); 798 } 799 800 // Other Number and HomeFaxNumber 801 cvData.cvOtherNumber = com.gContactSync.ABOverlay.makeDescElement("OtherNumber", "CardViewText"); 802 cvData.cvHomeFaxNumber = com.gContactSync.ABOverlay.makeDescElement("HomeFaxNumber", "CardViewText"); 803 vbox = document.getElementById("cvbPhone"); 804 vbox.appendChild(cvData.cvHomeFaxNumber); 805 vbox.appendChild(cvData.cvOtherNumber); 806 807 // Add a description where the mailing lists the selected contact is in 808 // will appear, if possible 809 if (GetSelectedDirectory !== undefined) { 810 var desc = document.createElement("description"); 811 cvData.cvLists = document.createTextNode("1"); 812 desc.style.paddingTop = "6px"; 813 desc.appendChild(cvData.cvLists); 814 vbox = document.getElementById("CardViewInnerBox"); 815 vbox.insertBefore(desc, document.getElementById("CardTitle").nextSibling); 816 } else { 817 cvData.cvLists = null; 818 } 819 }, 820 /** 821 * Makes and returns a <description> element of the given class and with an ID 822 * of aName with a prefix of "cv" 823 * @param aName {string} The ID of the element that will be prefixed with a 824 * "cv" 825 * @param aClass {string} The class of the element. 826 * @returns {XML} A new <description> element. 827 */ 828 makeDescElement: function ABOverlay_makeDescElement(aName, aClass) { 829 var elem = document.createElement("description"); 830 elem.setAttribute("class", aClass); 831 elem.setAttribute("id", "cv" + aName); 832 return elem; 833 }, 834 /** 835 * Adds a 'Reset' menuitem to the Address Book contaxt menu for the list on 836 * the left side of the Address Book window. 837 */ 838 addResetContext: function ABOverlay_addResetContext() { 839 var replaceFrom = document.createElement("menuitem"), 840 replaceTo = document.createElement("menuitem"); 841 842 replaceFrom.id = "dirTreeContext-replaceFrom"; 843 replaceTo.id = "dirTreeContext-replaceTo"; 844 replaceFrom.setAttribute("label", com.gContactSync.StringBundle.getStr("reset")); 845 replaceFrom.setAttribute("accesskey", com.gContactSync.StringBundle.getStr("resetKey")); 846 replaceFrom.setAttribute("oncommand", "com.gContactSync.ABOverlay.resetSelectedAB()"); 847 replaceTo.setAttribute("label", com.gContactSync.StringBundle.getStr("replaceTo")); 848 replaceTo.setAttribute("accesskey", com.gContactSync.StringBundle.getStr("replaceToKey")); 849 replaceTo.setAttribute("oncommand", "com.gContactSync.ABOverlay.replaceToSelectedAB()"); 850 document.getElementById("dirTreeContext").appendChild(replaceFrom); 851 document.getElementById("dirTreeContext").appendChild(replaceTo); 852 }, 853 /** 854 * Resets the currently selected address book after showing a confirmation 855 * dialog. 856 */ 857 resetSelectedAB: function ABOverlay_resetSelectedAB() { 858 var dirTree = document.getElementById("dirTree"); 859 var selected = dirTree.builderView.getResourceAtIndex(dirTree.currentIndex); 860 var ab = new com.gContactSync.GAbManager.getGAbByURI(selected.Value); 861 // make sure the AB was not already reset 862 if (ab.mPrefs.reset === "true") { 863 com.gContactSync.alert(com.gContactSync.StringBundle.getStr("alreadyReset")); 864 return; 865 } 866 // show a confirm dialog to make sure the user knows what's about to happen 867 if (com.gContactSync.confirm(com.gContactSync.StringBundle.getStr("resetConfirm2"))) { 868 if (ab.reset()) { 869 var restartStr = com.gContactSync.StringBundle.getStr("pleaseRestart"); 870 com.gContactSync.Preferences.setSyncPref("needRestart", true); 871 this.setStatusBarText(restartStr); 872 com.gContactSync.alertError(restartStr); 873 } 874 } 875 }, 876 /** 877 * Updates the LastModifiedDate of all contacts in the selected AB. 878 */ 879 replaceToSelectedAB: function ABOverlay_replaceToSelectedAB() { 880 var dirTree = document.getElementById("dirTree"); 881 var selected = dirTree.builderView.getResourceAtIndex(dirTree.currentIndex); 882 var ab = new com.gContactSync.GAbManager.getGAbByURI(selected.Value); 883 ab.replaceToServer(); 884 com.gContactSync.alert(com.gContactSync.StringBundle.getStr("replaceToComplete")); 885 }, 886 /** 887 * Fixes the description style as set (accidentally?) by the 888 * Duplicate Contacts Manager extension in duplicateContactsManager.css 889 * It appears that the new description style was applied to addressbook.xul 890 * on accident when it was meant only for duplicateEntriesWindow.xul 891 * 892 * @returns {boolean} true if the description style was removed. 893 */ 894 fixDescriptionStyle: function ABOverlay_fixDescriptionStyle() { 895 // Make sure this is addressbook.xul only 896 if (document.location && document.location.href.indexOf("/addressbook.xul") != -1) { 897 var ss = document.styleSheets; 898 var s; 899 // Iterate through each stylesheet and look for one from 900 // Duplicate Contacts Manager 901 for (var i = 0; i < ss.length; i++) { 902 // If this is duplicateContactsManager.css then remove the 903 // description style 904 if (ss[i] && ss[i].href == "chrome://duplicatecontactsmanager/skin/duplicateContactsManager.css") { 905 var rules = ss[i].cssRules; 906 for (var j = 0; j < rules.length; j++) { 907 if (rules[j].selectorText == "description") { 908 ss[i].deleteRule(j); 909 return true; 910 } 911 } 912 } 913 } 914 } 915 return false; 916 } 917 } 918