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-2009
 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 /**
 42  * A class for storing and editing the XML feed for a Group in Google Contacts.
 43  * @param aXml {XML Element} The XML representation of the group.
 44  *                           If not supplied then a new group is created.
 45  * @param aTitle {string}    The title for the group, if new.
 46  * @class
 47  * @constructor
 48  */
 49 com.gContactSync.Group = function gCS_Group(aXml, aTitle) {
 50   if (!aXml) {
 51     if (!aTitle) {
 52       throw "Error - No title or XML passed to the Group constructor";
 53     }
 54     var atom     = com.gContactSync.gdata.namespaces.ATOM,
 55         gd       = com.gContactSync.gdata.namespaces.GD,
 56         gcontact = com.gContactSync.gdata.namespaces.GCONTACT,
 57         xml      = document.createElementNS(atom.url, atom.prefix + "entry"),
 58         category = document.createElementNS(atom.url, atom.prefix + "category"),
 59         title   = document.createElementNS(atom.url, atom.prefix + "title"),
 60         text    = document.createTextNode(aTitle);
 61     category.setAttribute("scheme", gd.url + "/#kind");
 62     category.setAttribute("term", gcontact.url + "/#group");
 63     xml.appendChild(category);
 64     title.appendChild(text);
 65     xml.appendChild(title);
 66     this.xml    = xml;
 67     this.mTitle = aTitle;
 68   }
 69   else {
 70     this.xml    = aXml;
 71     this.mTitle = this.getTitle();
 72   }
 73 };
 74 
 75 com.gContactSync.Group.prototype = {
 76   /**
 77    * Sets the title of this Group.
 78    * @param aTitle The new title for this Group.
 79    */
 80   setTitle: function Group_setTitle(aTitle) {
 81     if (!aTitle) {
 82       throw "Error - invalid title passed to Group.setTitle";
 83     }
 84 
 85     var atom  = com.gContactSync.gdata.namespaces.ATOM,
 86         title = this.xml.getElementsByTagNameNS(atom.url, "title")[0],
 87         text;
 88     if (title && title.value && title.value.indexOf("System Group") !== -1) {
 89       return; // cannot rename system groups
 90     }
 91     this.mTitle = aTitle;
 92     if (title) {
 93       if (title.childNodes[0]) {
 94         title.childNodes[0].nodeValue = aTitle;
 95       }
 96       else {
 97         text = document.createTextNode(aTitle);
 98         title.appendChild(text);
 99       }
100     }
101     else {
102       title    = document.createElementNS(atom.url, atom.prefix + "title");
103       text = document.createTextNode(aTitle);
104       title.appendChild(text);
105       this.xml.appendChild(title);
106     }
107   },
108   /**
109    * Returns the title of this Group.  If this is a system group, which is NOT
110    * translated through the API, then this method will return a localized name
111    * for this group.
112    * @returns {string} The title of this Group.
113    */
114   getTitle: function Group_getTitle() {
115     if (this.mTitle) {
116       return this.mTitle;
117     }
118     // System Groups aren't localized through the API, so this will find the
119     // system group's ID (Contact, Coworker, Family, or Friend) and return the
120     // localized version of that group
121     if (this.isSystemGroup()) {
122       var elem = this.xml.getElementsByTagNameNS(com.gContactSync.gdata.namespaces.GCONTACT.url,
123                                                  "systemGroup")[0],
124           id   = elem ? elem.getAttribute("id") : null;
125       if (id) {
126         this.mTitle = com.gContactSync.StringBundle.getStr(id);
127         if (this.mTitle) {
128           return this.mTitle;
129         }
130       }
131     }
132     var atom  = com.gContactSync.gdata.namespaces.ATOM,
133         title = this.xml.getElementsByTagNameNS(atom.url, "title")[0];
134     if (title && title.childNodes[0]) {
135       this.mTitle = title.childNodes[0].nodeValue ?
136                     title.childNodes[0].nodeValue.replace("System Group: ", "") : null;
137       return this.mTitle;
138     }
139     return null;
140   },
141   /**
142    * Returns the URL used to edit this Group.
143    * @returns {string} the URL used to edit this Group.
144    */
145   getEditURL: function Group_getEditURL() {
146     var atom   = com.gContactSync.gdata.namespaces.ATOM;
147     var arr    = this.xml.getElementsByTagNameNS(atom.url, "link"),
148         i      = 0,
149         length = arr.length;
150     for (; i < length; i++) {
151       if (arr[i].getAttribute("rel") === com.gContactSync.gdata.contacts.links.EditURL) {
152         return arr[i].getAttribute("href");
153       }
154     }
155     return null;
156   },
157   /**
158    * Retrieves and returns the ID of this Group.
159    * @returns {string} The ID of this Group.
160    */
161   getID: function Group_getID() {
162     var atom = com.gContactSync.gdata.namespaces.ATOM,
163         id   = this.xml.getElementsByTagNameNS(atom.url, "id")[0];
164     if (id && id.childNodes[0]) {
165       return com.gContactSync.fixURL(id.childNodes[0].nodeValue);
166     }
167     return null;
168   },
169   /**
170    * Removes all of the extended properties from this Group.
171    */
172   removeExtendedProperties: function Group_removeExtendedProperties() {
173     var arr = this.xml.getElementsByTagNameNS(com.gContactSync.gdata.namespaces.GD.url, "extendedProperty"),
174         i   = arr.length - 1;
175     for (; i > -1 ; i--) {
176       this.xml.removeChild(arr[i]);
177     }
178   },
179   /**
180    * Returns the extended property of this group's XML whose value for the
181    * name attribute matches aName, if any.
182    * @param aName {string} The value of the name attribute to find.
183    * @returns {string} The value of an extended property whose name is the value of aName.
184    */
185   getExtendedProperty: function Group_getExtendedProperty(aName) {
186     var arr    = this.xml.getElementsByTagNameNS(com.gContactSync.gdata.namespaces.GD.url, "extendedProperty"),
187         i      = 0,
188         length = arr.length;
189     for (; i < length; i++) {
190       if (arr[i].getAttribute("name") === aName) {
191         return arr[i].getAttribute("value");
192       }
193     }
194     return null;
195   },
196   /**
197    * Gets the last modified date from the group's XML feed in milliseconds since
198    * 1970
199    * @returns {int} The last modified date of the group in milliseconds since
200    *               1970.
201    */
202   getLastModifiedDate: function Group_getLastModifiedDate() {
203     try {
204       var sModified = this.xml.getElementsByTagName('updated')[0].childNodes[0].nodeValue,
205          year      = sModified.substring(0, 4),
206          month     = sModified.substring(5, 7),
207          day       = sModified.substring(8, 10),
208          hrs       = sModified.substring(11, 13),
209          mins      = sModified.substring(14, 16),
210          sec       = sModified.substring(17, 19),
211          ms        = sModified.substring(20, 23);
212       return parseInt(Date.UTC(year, parseInt(month, 10) - 1, day, hrs, mins, sec, ms), 10);
213     }
214     catch (e) {
215       com.gContactSync.LOGGER.LOG_WARNING("Unable to get last modified date from a group:\n" + e);
216     }
217     return 0;
218   },
219   /**
220    * Sets an extended property with the given name and value if there are less
221    * than 10 existing.  Logs a warning if there are already 10 or more and does
222    * not add the property.
223    * @param aName  {string} The name of the property.
224    * @param aValue {string} The value of the property.
225    */
226   setExtendedProperty: function Group_setExtendedProperty(aName, aValue) {
227     if (this.xml.getElementsByTagNameNS(com.gContactSync.gdata.namespaces.GD.url,
228         "extendedProperty").length >= 10) {
229       com.gContactSync.LOGGER.LOG_WARNING("Attempt to add too many properties aborted");
230       return;
231     }
232     if (aValue && aValue !== "") {
233       var property = document.createElementNS(com.gContactSync.gdata.namespaces.GD.url,
234                                               "extendedProperty");
235       property.setAttribute("name", aName);
236       property.setAttribute("value", aValue);
237       this.xml.appendChild(property);
238     }
239   },
240   /**
241    * Returns true if this group is one of Google's system groups.
242    * These currently are:
243    *  - My Contacts
244    *  - Coworkers
245    *  - Family
246    *  - Friends
247    * @returns {boolean} True if this group is a system group.
248    */
249   isSystemGroup: function Group_isSystemGroup() {
250     var nodes = this.xml.getElementsByTagNameNS(com.gContactSync.gdata.namespaces.GCONTACT.url,
251                                                 "systemGroup");
252     return nodes && nodes.length > 0;
253   },
254   /**
255    * Returns the ID of the gContact:systemGroup tag, if any.
256    * @returns {string} The ID of the system group, if any.
257    */
258   getSystemId: function Group_getSystemId() {
259     var nodes = this.xml.getElementsByTagNameNS(com.gContactSync.gdata.namespaces.GCONTACT.url,
260                                                 "systemGroup");
261     if (!nodes || !nodes.length || !nodes[0]) return null;
262     return nodes[0].getAttribute("id");
263   }  
264 };
265