1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 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) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * @overview 26 * This file contains a setting class. 27 */ 28 29 /** 30 * Creates a setting. 31 * @class 32 * This class represents a single setting. A setting's default value never changes; it 33 * is available in case the user wishes to restore the current value to the default. 34 * Most but not all settings have a corollary on the server side. Settings that don't 35 * will depend on the environment or user activity to get their value. 36 * 37 * @author Conrad Damon 38 * 39 * @param {String} id a unique ID 40 * @param {Hash} params a hash of parameters 41 * @param {String} params.name the name of the pref or attr on the server 42 * @param {constant} params.type config, pref, or COS (see <code>ZmSetting.T_</code> constants) 43 * @param {constant} params.dataType string, int, or boolean 44 * @param {Object} params.defaultValue the default value 45 * @param {Boolean} params.isGlobal if <code>true</code>, this setting is global across accounts 46 * @param {Boolean} params.isImplicit if <code>true</code>, this setting is not represented in Preferences 47 * 48 * @extends ZmModel 49 */ 50 ZmSetting = function(id, params) { 51 52 if (arguments.length == 0) return; 53 ZmModel.call(this, ZmEvent.S_SETTING); 54 55 this.id = id; 56 this.name = params.name; 57 this.type = params.type; 58 this.dataType = params.dataType || ZmSetting.D_STRING; 59 this.defaultValue = params.defaultValue; 60 this.canPreset = params.canPreset; 61 if (this.type == ZmSetting.T_METADATA) { 62 this.section = params.section; 63 } 64 if (params.isGlobal) { 65 ZmSetting.IS_GLOBAL[id] = true; 66 } 67 if (params.isImplicit) { 68 ZmSetting.IS_IMPLICIT[id] = true; 69 } 70 71 if (this.dataType == ZmSetting.D_HASH) { 72 this.value = {}; 73 this.defaultValue = {}; 74 } else if (this.dataType == ZmSetting.D_LIST) { 75 this.value = []; 76 this.defaultValue = []; 77 } else { 78 this.value = null; 79 } 80 81 this.dontSaveDefault = params.dontSaveDefault; 82 }; 83 84 ZmSetting.prototype = new ZmModel; 85 ZmSetting.prototype.constructor = ZmSetting; 86 87 // setting types 88 /** 89 * Defines the "config" type. 90 */ 91 ZmSetting.T_CONFIG = "config"; 92 /** 93 * Defines the "COS" type. 94 */ 95 ZmSetting.T_COS = "cos"; 96 /** 97 * Defines the "domain" type. 98 */ 99 ZmSetting.T_DOMAIN = "domain"; 100 /** 101 * Defines the "meta-data" type. 102 */ 103 ZmSetting.T_METADATA = "meta"; 104 /** 105 * Defines the "pref" type. 106 */ 107 ZmSetting.T_PREF = "pref"; 108 /** 109 * Defines the "pseudo" type. 110 */ 111 ZmSetting.T_PSEUDO = "pseudo"; 112 113 // metadata sections 114 ZmSetting.M_IMPLICIT = "implicit"; 115 ZmSetting.M_OFFLINE = "offline"; 116 ZmSetting.M_ZIMLET = "zimlet"; 117 118 // setting data types 119 ZmSetting.D_STRING = "string"; // default type 120 ZmSetting.D_INT = "int"; 121 ZmSetting.D_BOOLEAN = "boolean"; 122 ZmSetting.D_LDAP_TIME = "ldap_time"; 123 ZmSetting.D_HASH = "hash"; 124 ZmSetting.D_LIST = "list"; 125 ZmSetting.D_NONE = "NONE"; // placeholder setting 126 127 // constants used as setting values 128 // TODO: these should be defined in their respective apps 129 /** 130 * Defines the "all" ACL grantee type. 131 * @type String 132 */ 133 ZmSetting.ACL_AUTH = "all"; 134 /** 135 * Defines the "group" ACL grantee type. 136 * @type String 137 */ 138 ZmSetting.ACL_GROUP = "grp"; 139 /** 140 * Defines the "none" ACL grantee type. 141 * @type String 142 */ 143 ZmSetting.ACL_NONE = "none"; 144 /** 145 * Defines the "public" ACL grantee type. 146 * @type String 147 */ 148 ZmSetting.ACL_PUBLIC = "pub"; 149 /** 150 * Defines the "domain" ACL grantee type. 151 * @type String 152 */ 153 ZmSetting.ACL_DOMAIN = "dom"; 154 /** 155 * Defines the "user" ACL grantee type. 156 * @type String 157 */ 158 ZmSetting.ACL_USER = "usr"; 159 ZmSetting.CAL_DAY = "day"; 160 ZmSetting.CAL_LIST = "list"; 161 ZmSetting.CAL_MONTH = "month"; 162 ZmSetting.CAL_WEEK = "week"; 163 ZmSetting.CAL_WORK_WEEK = "workWeek"; 164 ZmSetting.CAL_VISIBILITY_PRIV = "private"; 165 ZmSetting.CAL_VISIBILITY_PUB = "public"; 166 ZmSetting.CLIENT_ADVANCED = "advanced"; // zimbraPrefClientType 167 ZmSetting.CLIENT_STANDARD = "standard"; 168 ZmSetting.COMPOSE_FONT_COLOR = "#000000"; // zimbraPrefHtmlEditorDefaultFontColor 169 ZmSetting.COMPOSE_FONT_FAM = "arial,helvetica,sans-serif"; // zimbraPrefHtmlEditorDefaultFontFamily 170 ZmSetting.COMPOSE_FONT_SIZE = AjxMessageFormat.format(ZmMsg.pt,"12"); // zimbraPrefHtmlEditorDefaultFontSize 171 ZmSetting.LTR = "LTR"; 172 ZmSetting.RTL = "RTL"; 173 ZmSetting.COMPOSE_TEXT = "text"; // zimbraPrefComposeFormat 174 ZmSetting.COMPOSE_HTML = "html"; 175 ZmSetting.CV_CARDS = "cards"; // zimbraPrefContactsInitialView 176 ZmSetting.CV_LIST = "list"; 177 ZmSetting.DEDUPE_NONE = "dedupeNone"; // zimbraPrefDedupeMessagesSentToSelf 178 ZmSetting.DEDUPE_SECOND = "secondCopyifOnToOrCC"; 179 ZmSetting.DEDUPE_INBOX = "moveSentMessageToInbox"; 180 ZmSetting.DEDUPE_ALL = "dedupeAll"; 181 ZmSetting.DELETE_SELECT_NEXT = "next"; // zimbraPrefMailSelectAfterDelete 182 ZmSetting.DELETE_SELECT_PREV = "previous"; 183 ZmSetting.DELETE_SELECT_ADAPT = "adaptive"; 184 ZmSetting.GROUP_BY_CONV = "conversation"; // zimbraPrefGroupMailBy 185 ZmSetting.GROUP_BY_MESSAGE = "message"; 186 ZmSetting.HTTP_DEFAULT_PORT = 80; 187 ZmSetting.HTTPS_DEFAULT_PORT = 443; 188 ZmSetting.INC_NONE = "includeNone"; // zimbraPrefReplyIncludeOriginalText / zimbraPrefForwardIncludeOriginalText 189 ZmSetting.INC_ATTACH = "includeAsAttachment"; 190 ZmSetting.INC_BODY = "includeBody"; // deprecated - same as includeBodyAndHeaders 191 ZmSetting.INC_BODY_ONLY = "includeBodyOnly"; 192 ZmSetting.INC_BODY_PRE = "includeBodyWithPrefix"; 193 ZmSetting.INC_BODY_HDR = "includeBodyAndHeaders"; 194 ZmSetting.INC_BODY_PRE_HDR = "includeBodyAndHeadersWithPrefix"; 195 ZmSetting.INC_SMART = "includeSmart"; 196 ZmSetting.INC_SMART_PRE = "includeSmartWithPrefix"; 197 ZmSetting.INC_SMART_HDR = "includeSmartAndHeaders"; 198 ZmSetting.INC_SMART_PRE_HDR = "includeSmartAndHeadersWithPrefix"; 199 ZmSetting.MARK_READ_NONE = -1; // zimbraPrefMarkMsgRead 200 ZmSetting.MARK_READ_NOW = 0; // zimbraPrefMarkMsgRead 201 ZmSetting.MARK_READ_TIME = 1; // zimbraPrefMarkMsgRead 202 ZmSetting.PRINT_FONT_SIZE = AjxMessageFormat.format(ZmMsg.pt,"12"); // zimbraPrefDefaultPrintFontSize 203 ZmSetting.PROTO_HTTP = "http:"; 204 ZmSetting.PROTO_HTTPS = "https:"; 205 ZmSetting.PROTO_MIXED = "mixed:"; 206 ZmSetting.RIGHT_VIEW_FREE_BUSY = "viewFreeBusy"; 207 ZmSetting.RIGHT_INVITE = "invite"; 208 ZmSetting.RP_BOTTOM = "bottom"; // zimbraPrefReadingPaneLocation / zimbraPrefConvReadingPaneLocation / zimbraPrefTasksReadingPaneLocation / zimbraPrefBriefcaseReadingPaneLocation 209 ZmSetting.RP_OFF = "off"; 210 ZmSetting.RP_RIGHT = "right"; 211 ZmSetting.SIG_INTERNET = "internet"; // zimbraPrefMailSignatureStyle 212 ZmSetting.SIG_OUTLOOK = "outlook"; 213 214 // values for the 'fetch' param of SearchConvRequest 215 ZmSetting.CONV_FETCH_NONE = "0"; 216 ZmSetting.CONV_FETCH_FIRST_MATCHING = "1"; 217 ZmSetting.CONV_FETCH_FIRST = "!"; 218 ZmSetting.CONV_FETCH_UNREAD = "u"; 219 ZmSetting.CONV_FETCH_UNREAD_OR_FIRST_MATCHING = "u1"; 220 ZmSetting.CONV_FETCH_UNREAD_OR_FIRST = "u!"; 221 ZmSetting.CONV_FETCH_UNREAD_OR_BOTH_FIRST = "u1!"; 222 ZmSetting.CONV_FETCH_MATCHES = "hits"; 223 ZmSetting.CONV_FETCH_MATCHES_OR_FIRST = "hits!"; 224 ZmSetting.CONV_FETCH_ALL = "all"; 225 226 // License status (network only) 227 ZmSetting.LICENSE_GOOD = "OK"; 228 ZmSetting.LICENSE_NOT_INSTALLED = "NOT_INSTALLED"; 229 ZmSetting.LICENSE_NOT_ACTIVATED = "NOT_ACTIVATED"; 230 ZmSetting.LICENSE_FUTURE = "IN_FUTURE"; 231 ZmSetting.LICENSE_EXPIRED = "EXPIRED"; 232 ZmSetting.LICENSE_BAD = "INVALID"; 233 ZmSetting.LICENSE_GRACE = "LICENSE_GRACE_PERIOD"; 234 ZmSetting.LICENSE_ACTIV_GRACE = "ACTIVATION_GRACE_PERIOD"; 235 236 // warning messages for bad license statuses 237 ZmSetting.LICENSE_MSG = {}; 238 ZmSetting.LICENSE_MSG[ZmSetting.LICENSE_NOT_INSTALLED] = ZmMsg.licenseNotInstalled; 239 ZmSetting.LICENSE_MSG[ZmSetting.LICENSE_NOT_ACTIVATED] = ZmMsg.licenseNotActivated; 240 ZmSetting.LICENSE_MSG[ZmSetting.LICENSE_FUTURE] = ZmMsg.licenseExpired; 241 ZmSetting.LICENSE_MSG[ZmSetting.LICENSE_EXPIRED] = ZmMsg.licenseExpired; 242 ZmSetting.LICENSE_MSG[ZmSetting.LICENSE_BAD] = ZmMsg.licenseExpired; 243 244 // we need these IDs available when the app classes are parsed 245 ZmSetting.LOCALE_NAME = "LOCALE_NAME"; 246 ZmSetting.COMPOSE_INIT_DIRECTION= "COMPOSE_INIT_DIRECTION"; 247 ZmSetting.SHOW_COMPOSE_DIRECTION_BUTTONS = "SHOW_COMPOSE_DIRECTION_BUTTONS"; 248 ZmSetting.FONT_NAME = "FONT_NAME"; 249 ZmSetting.FONT_SIZE = "FONT_SIZE"; 250 ZmSetting.SKIN_NAME = "SKIN_NAME"; 251 252 ZmSetting.BRIEFCASE_ENABLED = "BRIEFCASE_ENABLED"; 253 ZmSetting.CALENDAR_ENABLED = "CALENDAR_ENABLED"; 254 ZmSetting.CONTACTS_ENABLED = "CONTACTS_ENABLED"; 255 ZmSetting.MAIL_ENABLED = "MAIL_ENABLED"; 256 ZmSetting.OPTIONS_ENABLED = "OPTIONS_ENABLED"; 257 ZmSetting.PORTAL_ENABLED = "PORTAL_ENABLED"; 258 ZmSetting.SEARCH_ENABLED = "SEARCH_ENABLED"; 259 ZmSetting.SOCIAL_ENABLED = "SOCIAL_ENABLED"; 260 ZmSetting.TASKS_ENABLED = "TASKS_ENABLED"; 261 ZmSetting.VOICE_ENABLED = "VOICE_ENABLED"; 262 ZmSetting.TAGGING_ENABLED = "TAGGING_ENABLED"; 263 ZmSetting.CHAT_FEATURE_ENABLED = "CHAT_FEATURE_ENABLED"; 264 ZmSetting.CHAT_ENABLED = "CHAT_ENABLED"; 265 ZmSetting.CHAT_PLAY_SOUND = "CHAT_PLAY_SOUND"; 266 267 ZmSetting.CALENDAR_UPSELL_ENABLED = "CALENDAR_UPSELL_ENABLED"; 268 ZmSetting.CONTACTS_UPSELL_ENABLED = "CONTACTS_UPSELL_ENABLED"; 269 ZmSetting.MAIL_UPSELL_ENABLED = "MAIL_UPSELL_ENABLED"; 270 ZmSetting.SOCIAL_EXTERNAL_ENABLED = "SOCIAL_EXTERNAL_ENABLED"; 271 ZmSetting.SOCIAL_EXTERNAL_URL = "SOCIAL_EXTERNAL_URL"; 272 ZmSetting.VOICE_UPSELL_ENABLED = "VOICE_UPSELL_ENABLED"; 273 274 //user selected font 275 ZmSetting.FONT_CLASSIC = "classic"; 276 ZmSetting.FONT_MODERN = "modern"; 277 ZmSetting.FONT_WIDE = "wide"; 278 ZmSetting.FONT_SYSTEM = "system"; 279 280 //user selected font size 281 ZmSetting.FONT_SIZE_SMALL = "small"; 282 ZmSetting.FONT_SIZE_NORMAL = "normal"; 283 ZmSetting.FONT_SIZE_LARGE = "large"; 284 ZmSetting.FONT_SIZE_LARGER = "larger"; 285 286 287 // name for dynamic CSS class created from user font prefs 288 ZmSetting.USER_FONT_CLASS = "userFontPrefs"; 289 290 //task filterby setting 291 ZmSetting.TASK_FILTER_ALL = ""; 292 ZmSetting.TASK_FILTER_TODO = "TODO"; 293 ZmSetting.TASK_FILTER_COMPLETED = "COMPLETED"; 294 ZmSetting.TASK_FILTER_WAITING = "WAITING"; 295 ZmSetting.TASK_FILTER_DEFERRED = "DEFERRED"; 296 ZmSetting.TASK_FILTER_INPROGRESS = "INPROGRESS"; 297 ZmSetting.TASK_FILTER_NOTSTARTED = "NOTSTARTED"; 298 299 // hash of global settings 300 ZmSetting.IS_GLOBAL = {}; 301 302 // hash of implicit settings 303 ZmSetting.IS_IMPLICIT = {}; 304 305 // hash of implicit settings that have been changed during the current session 306 ZmSetting.CHANGED_IMPLICIT = {}; 307 308 // Send As and Send On Behalf Of settings 309 ZmSetting.SEND_AS = "sendAs"; 310 ZmSetting.SEND_ON_BEHALF_OF = "sendOnBehalfOf"; 311 312 /** 313 * Returns a string representation of the object. 314 * 315 * @return {String} a string representation of the object 316 */ 317 ZmSetting.prototype.toString = 318 function() { 319 return this.name + ": " + this.value; 320 }; 321 322 /** 323 * Gets the current value of this setting. 324 * 325 * @param {String} key the optional key for use by hash table data type 326 * @param {Boolean} serialize if <code>true</code>, serialize non-string value into string 327 * @return {Object} the value 328 */ 329 ZmSetting.prototype.getValue = 330 function(key, serialize) { 331 332 var value = null; 333 if (this.value != null) { 334 value = key ? this.value[key] : this.value; 335 } else if (this.defaultValue != null) { 336 value = key ? this.defaultValue[key] : this.defaultValue; 337 } else { 338 return null; 339 } 340 341 if(this.dontSaveDefault && serialize && !key){ 342 value = this.getRefinedValue(value); 343 } 344 345 return serialize ? ZmSetting.serialize(value, this.dataType) : value; 346 }; 347 348 ZmSetting.prototype.getRefinedValue = 349 function(value){ 350 if(this.dataType == ZmSetting.D_HASH){ 351 var refinedValue = {}, dValue = this.defaultValue; 352 for(var key in value){ 353 refinedValue[key] = (dValue[key] != value[key]) ? value[key] : ""; 354 } 355 return refinedValue; 356 } 357 return value; 358 }; 359 360 /** 361 * Gets the original value of this setting. 362 * 363 * @param {String} key the optional key for use by hash table data type 364 * @param {Boolean} serialize if <code>true</code>, serialize non-string value into string 365 * @return {Object} the value 366 */ 367 ZmSetting.prototype.getOrigValue = 368 function(key, serialize) { 369 370 var origValue = null; 371 if (this.origValue != null) { 372 origValue = key ? this.origValue[key] : this.origValue; 373 } else if (this.defaultValue != null) { 374 origValue = key ? this.defaultValue[key] : this.defaultValue; 375 } else { 376 return null; 377 } 378 379 return serialize ? ZmSetting.serialize(origValue, this.dataType) : origValue; 380 }; 381 382 /** 383 * Gets the default value of this setting. 384 * 385 * @param {String} key the optional key for use by hash table data type 386 * @return {Object} the value 387 */ 388 ZmSetting.prototype.getDefaultValue = 389 function(key, serialize) { 390 var value = key ? this.defaultValue[key] : this.defaultValue; 391 return serialize ? ZmSetting.serialize(value, this.dataType) : value; 392 }; 393 394 /** 395 * Sets the current value of this setting, performing any necessary data type conversion. 396 * 397 * @param {Object} value the new value for the setting 398 * @param {String} key optional key for use by hash table data type 399 * @param {Boolean} setDefault if <code>true</code>, also set the default value 400 * @param {Boolean} skipNotify if <code>true</code>, do not notify listeners 401 * @param {Boolean} skipImplicit if <code>true</code>, do not check for change to implicit pref 402 */ 403 ZmSetting.prototype.setValue = 404 function(value, key, setDefault, skipNotify, skipImplicit) { 405 406 var newValue = value; 407 var changed = Boolean(newValue != this.value); 408 if (this.dataType == ZmSetting.D_STRING) { 409 this.value = newValue; 410 } else if (this.dataType == ZmSetting.D_INT) { 411 newValue = parseInt(value); 412 if (isNaN(newValue)) { // revert to string if NaN 413 newValue = value; 414 } 415 changed = Boolean(newValue != this.value); 416 this.value = newValue; 417 } else if (this.dataType == ZmSetting.D_BOOLEAN) { 418 if (typeof(newValue) == "string") { 419 newValue = (newValue.toLowerCase() === "true"); 420 } 421 changed = Boolean(newValue != this.value); 422 this.value = newValue; 423 } else if (this.dataType == ZmSetting.D_LDAP_TIME) { 424 var lastChar = (newValue.toLowerCase) ? lastChar = (newValue.toLowerCase()).charAt(newValue.length-1) : null; 425 var num = parseInt(newValue); 426 // convert to seconds 427 if (lastChar == 'd') { 428 newValue = num * 24 * 60 * 60; 429 } else if (lastChar == 'h') { 430 newValue = num * 60 * 60; 431 } else if (lastChar == 'm') { 432 newValue = num * 60; 433 } else { 434 newValue = num; // default 435 } 436 changed = Boolean(newValue != this.value); 437 this.value = newValue; 438 } else if (this.dataType == ZmSetting.D_HASH) { 439 changed = true; 440 if (key) { 441 if (newValue) { 442 changed = Boolean(newValue != this.value[key]); 443 this.value[key] = newValue; 444 } else { 445 delete this.value[key]; 446 } 447 } else { 448 this.value = newValue; 449 } 450 } else if (this.dataType == ZmSetting.D_LIST) { 451 if (newValue instanceof Array) { 452 this.value = newValue; 453 } else { 454 this.value.push(newValue); 455 } 456 changed = true; 457 } 458 459 if (setDefault) { 460 if (key) { 461 this.defaultValue[key] = this.value[key]; 462 } else { 463 this.defaultValue = this.value; 464 } 465 } 466 467 if (ZmSetting.IS_IMPLICIT[this.id] && changed && !skipImplicit) { 468 if (skipNotify) { 469 ZmSetting.CHANGED_IMPLICIT[this.id] = true; 470 } else { 471 this._notify(ZmEvent.E_MODIFY, key); 472 return; 473 } 474 } 475 476 // Setting an internal pref is equivalent to saving it, so we should notify 477 if (!this.name && !skipNotify) { 478 this._notify(ZmEvent.E_MODIFY, key); 479 } 480 }; 481 482 /** 483 * Handles modify notification. 484 * 485 * @param {Object} obj the object 486 */ 487 ZmSetting.prototype.notifyModify = 488 function(obj) { 489 if (this.id == ZmSetting.QUOTA_USED && obj._name == "mbx" && obj.s != null) { 490 this.setValue(obj.s); 491 this._notify(ZmEvent.E_MODIFY, {account:obj.account}); 492 } 493 }; 494 495 ZmSetting.prototype.copyValue = 496 function() { 497 498 if (this.dataType == ZmSetting.D_HASH) { 499 return AjxUtil.hashCopy(this.value); 500 } else if (this.dataType == ZmSetting.D_LIST) { 501 return this.value.concat(); 502 } else { 503 return this.value; 504 } 505 }; 506 507 ZmSetting.serialize = 508 function(value, dataType) { 509 510 if (dataType == ZmSetting.D_BOOLEAN) { 511 value = value ? "TRUE" : "FALSE"; 512 } else if (dataType == ZmSetting.D_HASH) { 513 var keys = []; 514 for (var key in value) { 515 keys.push(key); 516 } 517 keys.sort(); 518 var pairs = []; 519 for (var j = 0; j < keys.length; j++) { 520 var key = keys[j]; 521 pairs.push([key, value[key]].join(":")); 522 } 523 value = pairs.join(","); 524 } else if (dataType == ZmSetting.D_LIST) { 525 value = value.join(","); 526 } 527 528 return value; 529 }; 530