1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. 5 * 6 * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: https://www.zimbra.com/license 9 * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15 10 * have been added to cover use of software over a computer network and provide for limited attribution 11 * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B. 12 * 13 * Software distributed under the License is distributed on an "AS IS" basis, 14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. 15 * See the License for the specific language governing rights and limitations under the License. 16 * The Original Code is Zimbra Open Source Web Client. 17 * The Initial Developer of the Original Code is Zimbra, Inc. All rights to the Original Code were 18 * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015. 19 * 20 * All portions of the code are Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * @overview 26 * This file contains a contact helper class. 27 * 28 */ 29 30 /** 31 * Default constructor for helper class. 32 * @class 33 * Miscellaneous contacts-related utility functions. So far, mostly things that 34 * {@link ZmContactPicker} and {@link ZmGroupView} both need to perform a contacts search and 35 * display results in a list view. 36 * 37 * @author Conrad Damon 38 */ 39 ZmContactsHelper = function() {}; 40 41 /** 42 * Performs a contact search (in either personal contacts or in the GAL) and populates 43 * the source list view with the results. 44 * 45 * @param {Hash} params a hash of parameters 46 * @param {Object} params.obj the object that is doing the search 47 * @param {String} params.query the query string to search on 48 * @param {String} params.queryHint the query hint (i.e. searching shared folders) 49 * @param {Boolean} params.ascending if <code>true</code>, sort in ascending order 50 * @param {int} params.lastId the ID of last item displayed (for pagination) 51 * @param {String} params.lastSortVal the value of sort field for above item 52 * @param {AjxCallback} params.respCallback the callback to call once response comes back from server 53 * @param {AjxCallback} params.errorCallback the callback to call if error returned from server 54 * @param {String} params.accountName the account to make search request on behalf of 55 * @param {Array} params.conds the conds to restrict the search by (array of {attr:"", op:"", value:""} hashes) 56 */ 57 ZmContactsHelper.search = 58 function(params) { 59 var o = params.obj; 60 if (o._searchButton) { 61 o._searchButton.setEnabled(false); 62 } 63 64 params.sortBy = params.ascending ? ZmSearch.NAME_ASC : ZmSearch.NAME_DESC; 65 params.types = AjxVector.fromArray([ZmItem.CONTACT]); 66 params.offset = params.offset || 0; 67 params.limit = ZmContactsApp.SEARCHFOR_MAX; 68 params.contactSource = o._contactSource; 69 params.field = "contact"; 70 71 var search = new ZmSearch(params); 72 search.execute({callback:params.respCallback, errorCallback:params.errorCallback}); 73 }; 74 75 /** 76 * Take the contacts and create a list of their email addresses (a contact may have more than one) 77 * 78 * @private 79 */ 80 ZmContactsHelper._processSearchResponse = 81 function(resp, includeContactsWithNoEmail) { 82 var vec = resp.getResults(ZmItem.CONTACT); 83 84 // Take the contacts and create a list of their email addresses (a contact may have more than one) 85 var list = []; 86 var a = vec.getArray(); 87 for (var i = 0; i < a.length; i++) { 88 var contact = a[i]; 89 if (contact.isGroup() && !contact.isDL) { 90 var members = contact.getGroupMembers().good.toString(AjxEmailAddress.SEPARATOR); 91 ZmContactsHelper._addContactToList(list, contact, members, true); 92 } else { 93 var emails = contact.isGal ? [contact.getEmail()] : contact.getEmails(); 94 for (var j = 0; j < emails.length; j++) { 95 ZmContactsHelper._addContactToList(list, contact, emails[j]); 96 } 97 if (includeContactsWithNoEmail && emails.length == 0) { 98 ZmContactsHelper._addContactToList(list, contact, null); 99 } 100 } 101 } 102 103 return list; 104 }; 105 106 /** 107 * @private 108 */ 109 ZmContactsHelper._addContactToList = 110 function(list, contact, addr, isGroup) { 111 112 var email = ZmContactsHelper._wrapContact(contact, addr, isGroup); 113 list.push(email); 114 }; 115 116 /** 117 * wrapps the contact inside a AjxEmailAddress object, and adds a couple extra fields to the AjxEmailAddress instance (value, contact, icon [which I'm not sure is used]) 118 * 119 * @param contact 120 * @param addr {String} optional. 121 * @param isGroup 122 */ 123 ZmContactsHelper._wrapContact = 124 function(contact, addr, isGroup) { 125 126 addr = addr || contact.getEmail(); 127 var fileAs = contact.getFileAs(); 128 var name = (fileAs != addr) ? fileAs : ""; //todo ??? this is weird. 129 var type = contact.isGal ? ZmContact.GROUP_GAL_REF : ZmContact.GROUP_CONTACT_REF; 130 var value = contact.isGal ? (contact.ref || contact.id) : contact.id; //defaulting to contact.id in the gal case since from GetContactsResponse the ref is not returned and we can end up with it cached without the ref. Probably need to fix that. 131 var displayName = contact.getFullNameForDisplay(); 132 133 var email = new AjxEmailAddress(addr, type, name, displayName, isGroup); 134 135 email.value = value; 136 email.id = Dwt.getNextId(); 137 email.__contact = contact; 138 email.icon = contact.getIcon(); 139 if (contact.isDL) { 140 email.isGroup = true; 141 email.canExpand = contact.canExpand; 142 var ac = window.parentAppCtxt || window.appCtxt; 143 ac.setIsExpandableDL(addr, email.canExpand); 144 } 145 return email; 146 }; 147 148 /** 149 * wrapps the inline address (there's no real ZmContact object) inside AjxEmailAddress and adds the value attribute to it. 150 * this is so we treat real contacts and inline contacts consistently throughout the rest of the code. 151 * 152 * @param value {String} - the inline email address and/or name (e.g. "john doe <john@doe.com>" or "john@doe.com") 153 */ 154 ZmContactsHelper._wrapInlineContact = 155 function(value) { 156 var email = AjxEmailAddress.parse(value); //from legacy data at least (not sure about new), the format might be something like "Inigo Montoya <inigo@theprincessbride.com>" so we have to parse. 157 if (!email) { 158 //this can happen when creating inline in contact group edit, and the user did not suply email address in the inline value 159 email = new AjxEmailAddress(value, null, value); 160 } 161 email.type = ZmContact.GROUP_INLINE_REF; 162 email.value = value; 163 email.id = Dwt.getNextId(); 164 return email; 165 }; 166 167 168 /** 169 * The items are AjxEmailAddress objects 170 * 171 * @private 172 */ 173 ZmContactsHelper._getEmailField = 174 function(html, idx, item, field, colIdx) { 175 if (field == ZmItem.F_TYPE) { 176 html[idx++] = AjxImg.getImageHtml(item.icon); 177 } else if (field == ZmItem.F_NAME) { 178 html[idx++] = '<span style="white-space:nowrap">'; 179 html[idx++] = AjxStringUtil.htmlEncode(item.name || ZmMsg.noName); 180 html[idx++] = "</span>"; 181 } else if (field == ZmItem.F_EMAIL) { 182 html[idx++] = AjxStringUtil.htmlEncode(item.address); 183 } else if (field == ZmItem.F_DEPARTMENT) { 184 if (item.__contact) { 185 html[idx++] = AjxStringUtil.htmlEncode(ZmContact.getAttr(item.__contact, ZmContact.F_department)); 186 } 187 } 188 return idx; 189 }; 190