1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 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) 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 ZmPriorityMessageFilterDialog = function() { 25 26 DwtDialog.call(this, {parent:appCtxt.getShell(), className:"ZmPriorityMessageFilterDialog", title:ZmMsg.activityStream}); 27 28 // set content 29 this.setContent(this._contentHtml()); 30 this._initialize(); 31 var okButton = this.getButton(DwtDialog.OK_BUTTON); 32 okButton.setText(ZmMsg.save); 33 this.setButtonListener(DwtDialog.OK_BUTTON, new AjxListener(this, this._okButtonListener)); 34 this._rules = AjxDispatcher.run("GetFilterRules"); 35 }; 36 37 ZmPriorityMessageFilterDialog.prototype = new DwtDialog; 38 ZmPriorityMessageFilterDialog.prototype.constructor = ZmPriorityMessageFilterDialog; 39 40 ZmPriorityMessageFilterDialog.prototype._contentHtml = 41 function() { 42 var html = "<div id='PRIORITYMESSAGE_PROMPT_FORM'>"; 43 return html; 44 }; 45 46 ZmPriorityMessageFilterDialog.prototype._initialize = 47 function() { 48 var streamListener = this._onMoveMsgIntoStream.bind(this); 49 var advancedListener = this._onAdvancedControls.bind(this); 50 var params = {}; 51 params.parent = this; 52 params.template = "prefs.Pages#PriorityMessageFilterPrompt"; 53 params.id = "PriorityInboxDialog"; 54 params.form = { 55 items: [ 56 { id: "MOVE_MSG_STREAM", type: "DwtCheckbox", label: ZmMsg.enableActivityStream, checked: false, onclick: streamListener}, 57 { id: "NOT_TO_ME", type: "DwtCheckbox", label: ZmMsg.moveNotToMe, checked: false}, 58 { id: "SELECT_FIELD", type: "DwtSelect", items:[ZmMsg.to, ZmMsg.toOrCc]}, 59 { id: "NOT_IN_ADDR", type: "DwtCheckbox", label: ZmMsg.moveNotInAddrBook, checked: false}, 60 { id: "DL_SUBSCRIBED", type: "DwtCheckbox", label: ZmMsg.moveMessagesFromDL, checked: true}, 61 { id: "MASS_MARKETING", type: "DwtCheckbox", label: ZmMsg.massMarketingMessages, checked: true} 62 ] 63 }; 64 this._priorityMessageForm = new DwtForm(params); 65 this._priorityMessageForm.setScrollStyle(DwtControl.CLIP); 66 var div = document.getElementById("PRIORITYMESSAGE_PROMPT_FORM"); 67 this._priorityMessageForm.appendElement(div); 68 69 this._moveMsgIntoStream = this._priorityMessageForm.getControl("MOVE_MSG_STREAM"); 70 this._notToMe = this._priorityMessageForm.getControl("NOT_TO_ME"); 71 this._selectField = this._priorityMessageForm.getControl("SELECT_FIELD"); 72 this._selectField.fixedButtonWidth(); 73 this._notInMyAddrBk = this._priorityMessageForm.getControl("NOT_IN_ADDR"); 74 this._dlSubscribedTo = this._priorityMessageForm.getControl("DL_SUBSCRIBED"); 75 this._massMarketing = this._priorityMessageForm.getControl("MASS_MARKETING"); 76 77 this._streamHash = {}; 78 this._streamHash[ZmFilterRule.TEST_BULK] = {control: this._massMarketing, negative: false}; 79 this._streamHash[ZmFilterRule.TEST_LIST] = {control: this._dlSubscribedTo, negative: false}; 80 this._streamHash[ZmFilterRule.TEST_ADDRBOOK] = {control: this._notInMyAddrBk, negative: true, headerValue: "from"}; 81 this._streamHash[ZmFilterRule.TEST_ME] = {control: this._notToMe, negative: true, headerValue: "to"}; 82 83 this._advancedControls = new DwtText({parent:this,className:"FakeAnchor"}); 84 this._advancedControls.setText(ZmMsg.advancedControls); 85 this._advancedControls.getHtmlElement().onclick = advancedListener; 86 this._advancedControls.replaceElement(document.getElementById("PriorityInboxAdvancedControls")); 87 }; 88 89 ZmPriorityMessageFilterDialog.prototype.popup = 90 function() { 91 var callback = new AjxCallback(this, this._handleResponseLoadRules); 92 this._rules.loadRules(true, callback); // make sure rules are loaded (for when we save) 93 94 DwtDialog.prototype.popup.call(this); 95 }; 96 97 ZmPriorityMessageFilterDialog.prototype._handleResponseLoadRules = 98 function() { 99 this._activityStreamRule = this._rules.getRuleByName(ZmMsg.activityStreamsRule); 100 this._setStreamSelections(); 101 }; 102 103 ZmPriorityMessageFilterDialog.prototype._onMoveMsgIntoStream = 104 function() { 105 var enabled = this._moveMsgIntoStream.isSelected(); 106 this._notToMe.setEnabled(enabled); 107 this._selectField.setEnabled(enabled); 108 this._notInMyAddrBk.setEnabled(enabled); 109 this._dlSubscribedTo.setEnabled(enabled); 110 this._massMarketing.setEnabled(enabled); 111 }; 112 113 ZmPriorityMessageFilterDialog.prototype._onAdvancedControls = 114 function(controlId) { 115 var filterRuleDialog = appCtxt.getFilterRuleDialog(); 116 var isPriority = false; 117 var rule = this._activityStreamRule; 118 119 if (rule) { 120 filterRuleDialog.popup(rule, true); 121 } 122 else { 123 //create rule with default conditions 124 var ruleName = isPriority ? ZmMsg.markAsPriorityRule : ZmMsg.activityStreamsRule; 125 var rule = new ZmFilterRule(ruleName, true, {}, {}); 126 rule.addAction(ZmFilterRule.A_FOLDER, ZmMsg.activityStreamsRule); 127 for (var id in this._streamHash) { 128 if (id == ZmFilterRule.TEST_ME) { 129 var meTestValue = this._selectField.getValue() == ZmMsg.to ? ZmFilterRule.C_ADDRESS_VALUE[ZmFilterRule.C_TO] : ZmFilterRule.C_ADDRESS_VALUE[ZmFilterRule.C_TO_CC]; 130 rule.addCondition(id, ZmFilterRule.OP_NOT_IS, null, meTestValue); 131 } 132 else if (id == ZmFilterRule.TEST_ADDRBOOK) { 133 rule.addCondition(id, ZmFilterRule.OP_NOT_IN ,"contacts", this._streamHash[id].headerValue); //Address in From not in Contacts 134 } 135 else { 136 rule.addCondition(id); 137 } 138 } 139 rule.setGroupOp(ZmFilterRule.GROUP_ANY); 140 filterRuleDialog.popup(rule, true); 141 } 142 }; 143 144 ZmPriorityMessageFilterDialog.prototype._setStreamSelections = 145 function() { 146 if (this._activityStreamRule) { 147 if (this._activityStreamRule.active) { 148 this._moveMsgIntoStream.setEnabled(true); 149 this._moveMsgIntoStream.setSelected(true); 150 } 151 else { 152 this._moveMsgIntoStream.setSelected(false); 153 } 154 var conditions = this._activityStreamRule.conditions; 155 //initialize checkboxes before loading them 156 this._massMarketing.setSelected(false); 157 this._dlSubscribedTo.setSelected(false); 158 this._notInMyAddrBk.setSelected(false); 159 this._notToMe.setSelected(false); 160 161 for (var c in conditions) { 162 var length = AjxUtil.isArray(conditions[c]) ? conditions[c].length : -1; 163 for (var i=0; i<length; i++) { 164 var isNegative = AjxUtil.isArray(conditions[c]) && conditions[c][i].negative ? (conditions[c][i].negative == "1") : false; 165 if (this._streamHash[c]) { 166 if (isNegative && (c == ZmFilterRule.TEST_ADDRBOOK || c == ZmFilterRule.TEST_ME)) { 167 var header = AjxUtil.isArray(conditions[c]) && conditions[c][i].header; 168 if (c == ZmFilterRule.TEST_ADDRBOOK) { 169 value = ZmFilterRule.C_FROM; 170 } 171 else if (c == ZmFilterRule.TEST_ME) { 172 if (header && header.toUpperCase() == ZmFilterRule.C_ADDRESS_VALUE[ZmFilterRule.C_TO].toUpperCase()) { 173 value = header; 174 this._selectField.setSelected(0); 175 } 176 else if (header && header.toUpperCase() == ZmFilterRule.C_ADDRESS_VALUE[ZmFilterRule.C_TO_CC].toUpperCase()) { 177 value = header; 178 this._selectField.setSelected(1); 179 } 180 } 181 //var value = (c == ZmFilterRule.TEST_ADDRBOOK) ? ZmFilterRule.C_FROM : ZmFilterRule.C_TO; 182 if (header && header.toLowerCase() == value.toLowerCase()) { 183 this._streamHash[c].control.setSelected(true); 184 this._streamHash[c].control.setEnabled(true); 185 } 186 } 187 else if (!isNegative && !(c == ZmFilterRule.TEST_ADDRBOOK || c == ZmFilterRule.TEST_ME)) { 188 this._streamHash[c].control.setSelected(true); 189 this._streamHash[c].control.setEnabled(true); 190 } 191 } 192 } 193 } 194 } 195 else { 196 this._moveMsgIntoStream.setSelected(false); 197 } 198 this._onMoveMsgIntoStream(); 199 }; 200 201 ZmPriorityMessageFilterDialog.prototype._okButtonListener = 202 function() { 203 //build filter 204 var foundCondition = false; 205 var needSave = false; 206 var condition = {}; 207 var activityRule = this._rules.getRuleByName(ZmMsg.activityStreamsRule); 208 209 //handle activity streams 210 foundCondition = false; 211 if (this._moveMsgIntoStream.isSelected()) { 212 var streamRule = new ZmFilterRule(ZmMsg.activityStreamsRule, true, {}, {}); 213 streamRule.addAction(ZmFilterRule.A_FOLDER, ZmMsg.activityStreamsRule); 214 streamRule.setGroupOp(ZmFilterRule.GROUP_ANY); 215 216 for (var id in this._streamHash) { 217 var control = this._streamHash[id].control; 218 var negative = this._streamHash[id].negative; 219 var headerValue = this._streamHash[id].headerValue; 220 if (control.isSelected()) { 221 if (id == ZmFilterRule.TEST_ME) { 222 var meTestValue = this._selectField.getValue() == ZmMsg.to ? ZmFilterRule.C_ADDRESS_VALUE[ZmFilterRule.C_TO] : ZmFilterRule.C_ADDRESS_VALUE[ZmFilterRule.C_TO_CC]; 223 streamRule.addCondition(id, ZmFilterRule.OP_NOT_IS, null, meTestValue); 224 } 225 else if (id == ZmFilterRule.TEST_ADDRBOOK) { 226 streamRule.addCondition(id, ZmFilterRule.OP_NOT_IN ,"contacts", headerValue); //Address in From not in Contacts 227 } 228 else { 229 streamRule.addCondition(id); 230 } 231 foundCondition = true; 232 } 233 else if (activityRule) { 234 if (id == ZmFilterRule.TEST_ME && this._activityStreamRule.conditions[ZmFilterRule.TEST_ME]) { 235 //if we uncheck the me filter we need to know which headerValue we are removing ("to" or "to,cc") 236 activityRule = this._removeCondition(activityRule, id, negative, this._activityStreamRule.conditions[ZmFilterRule.TEST_ME][0].headerValue); 237 } 238 else { 239 activityRule = this._removeCondition(activityRule, id, negative, headerValue); 240 } 241 } 242 } 243 244 if (foundCondition && activityRule) { 245 for (var id in streamRule.conditions) { 246 activityRule.conditions[id] = streamRule.conditions[id]; 247 } 248 249 for (var id in streamRule.actions) { 250 activityRule.actions[id] = streamRule.actions[id]; 251 } 252 253 activityRule.active = true; 254 needSave = true; 255 } 256 else if(foundCondition) { 257 this._rules.insertRule(streamRule); //insert last 258 needSave = true; 259 } 260 else if (activityRule) { 261 return this._handleConditionsError(ZmMsg.ruleNoConditonActivityFilter); 262 } 263 } 264 else if (activityRule) { 265 //set existing rule to be non-active 266 activityRule.active = false; 267 needSave = true; 268 } 269 270 if (needSave) { 271 this._rules.saveRules(null, true); 272 this._createActivityStreamsFolder(); 273 } 274 275 this.popdown(); 276 277 }; 278 279 ZmPriorityMessageFilterDialog.prototype._getButtonsContainerStartTemplate = 280 function() { 281 var html = "<div style='width: 250px; float: left;'><span id='PriorityInboxAdvancedControls'></span></div><div style='float:right;'>"; 282 html += DwtDialog.prototype._getButtonsContainerStartTemplate.call(this); 283 return html; 284 }; 285 286 ZmPriorityMessageFilterDialog.prototype._getButtonsContainerEndTemplate = 287 function() { 288 var html = "</div>"; 289 html += DwtDialog.prototype._getButtonsContainerEndTemplate.call(this); 290 return html; 291 }; 292 293 /** 294 * checks condition and value to determine if it should be removed; comparators are not checked 295 * @param rule 296 * @param condition 297 * @param isNegative 298 * @param headerValue 299 */ 300 ZmPriorityMessageFilterDialog.prototype._removeCondition = 301 function(rule, condition, isNegative, headerValue) { 302 var c = rule.conditions[condition]; 303 if (c) { 304 for (var i=0; i<c.length; i++) { 305 var negativeCheck = isNegative ? c[i].negative == "1" : !c[i].negative; 306 var headerCheck = headerValue ? c[i].header == headerValue : true; 307 if (condition == ZmFilterRule.TEST_CONVERSATIONS) { 308 headerCheck = headerValue ? c[i].where == headerValue : true; 309 } 310 if (negativeCheck && headerCheck) { 311 c.splice(i, 1); 312 rule.conditions[condition] = c; 313 } 314 } 315 } 316 return rule; 317 }; 318 319 ZmPriorityMessageFilterDialog.prototype._handleConditionsError = 320 function(msg) { 321 var msgDialog = appCtxt.getMsgDialog(); 322 msgDialog.setMessage(msg, DwtMessageDialog.CRITICAL_STYLE); 323 msgDialog.popup(); 324 }; 325 326 ZmPriorityMessageFilterDialog.prototype._createActivityStreamsFolder = 327 function() { 328 var jsonObj = {CreateFolderRequest:{_jsns:"urn:zimbraMail"}}; 329 var folder = jsonObj.CreateFolderRequest.folder = {l: ZmOrganizer.ID_ROOT, name: ZmMsg.activityStreamFolder, fie: 1, view: "message"}; 330 return appCtxt.getAppController().sendRequest({ 331 jsonObj: jsonObj, 332 asyncMode: true, 333 callback: new AjxCallback(this, this._handleActivityStreamsFolderCreate) 334 }); 335 }; 336 337 ZmPriorityMessageFilterDialog.prototype._handleActivityStreamsFolderCreate = 338 function(result) { 339 var resp = result && result._data && result._data.CreateFolderResponse; 340 if (resp) { 341 appCtxt.set(ZmSetting.MAIL_ACTIVITYSTREAM_FOLDER, resp.folder[0].id); 342 } 343 }; 344