1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2005, 2006, 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) 2005, 2006, 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 defines the Zimbra error dialog. 27 * 28 */ 29 30 /** 31 * Creates an error dialog. 32 * @class 33 * Creates an error dialog which will have a "Send Error Report" button. 34 * A normal {@link DwtMessageDialog} with a "Send Error Report" button that will post user info to the 35 * server when clicked. 36 * 37 * @param {Object} parent the parent 38 * @param {Hash} msgs a hash of messages 39 * @param {String} msgs.showDetails the show details message 40 * @param {String} msgs.hideDetails the hide details message 41 * 42 * @extends DwtMessageDialog 43 */ 44 ZmErrorDialog = function(parent, msgs) { 45 46 // go ahead and cache the navigator and subject info now (since it should never change) 47 this._strNav = this._getNavigatorInfo(); 48 this._subjPfx = this._getSubjectPrefix(); 49 50 var reportButton = new DwtDialog_ButtonDescriptor(ZmErrorDialog.REPORT_BUTTON, msgs.report, DwtDialog.ALIGN_LEFT); 51 var detailButton = new DwtDialog_ButtonDescriptor(ZmErrorDialog.DETAIL_BUTTON, msgs.showDetails, DwtDialog.ALIGN_LEFT); 52 DwtMessageDialog.call(this, {parent:parent, extraButtons:[reportButton, detailButton], id:"ErrorDialog"}); 53 54 this.registerCallback(ZmErrorDialog.REPORT_BUTTON, this._reportCallback, this); 55 this.registerCallback(ZmErrorDialog.DETAIL_BUTTON, this.showDetail, this); 56 57 this._showDetailsMsg = msgs.showDetails; 58 this._hideDetailsMsg = msgs.hideDetails; 59 60 this._setAllowSelection(); 61 }; 62 63 ZmErrorDialog.prototype = new DwtMessageDialog; 64 ZmErrorDialog.prototype.constructor = ZmErrorDialog; 65 66 /** 67 * Returns a string representation of the object. 68 * 69 * @return {String} a string representation of the object 70 */ 71 ZmErrorDialog.prototype.toString = 72 function() { 73 return "ZmErrorDialog"; 74 }; 75 76 // 77 // Consts 78 // 79 80 ZmErrorDialog.REPORT_BUTTON = "Report"; 81 ZmErrorDialog.DETAIL_BUTTON = "Detail"; 82 ZmErrorDialog.DEFAULT_REPORT_URL = "//www.zimbra.com/e/"; 83 84 // 85 // Data 86 // 87 88 ZmErrorDialog.prototype._detailsVisible = false; 89 ZmErrorDialog.prototype.CONTROLS_TEMPLATE = "zimbra.Widgets#ZmErrorDialogControls"; 90 91 // 92 // Public methods 93 // 94 95 /** 96 * Resets the dialog. 97 * 98 */ 99 ZmErrorDialog.prototype.reset = 100 function() { 101 this.setDetailString(); 102 DwtMessageDialog.prototype.reset.call(this); 103 }; 104 105 /** 106 * Sets the text to display when the "Show Details" button is pressed. 107 * 108 * @param {String} text the detail text 109 */ 110 ZmErrorDialog.prototype.setDetailString = 111 function(text) { 112 if (!(this._button[ZmErrorDialog.DETAIL_BUTTON])) { return; } 113 114 this._button[ZmErrorDialog.DETAIL_BUTTON].setVisible(text != null); 115 this._detailStr = text; 116 }; 117 118 /** 119 * Sets the message style (info/warning/critical) and content. 120 * 121 * @param {String} msgStr the message text 122 * @param {String} detailStr the detail text 123 * @param {constant} style the style (see {@link DwtMessageDialog} <code>_STYLE</code> constants) 124 * @param {String} title the dialog box title 125 */ 126 ZmErrorDialog.prototype.setMessage = 127 function(msgStr, detailStr, style, title) { 128 this._msgStr = msgStr; 129 this.setDetailString(detailStr); 130 this._msgStyle = style; 131 this._msgTitle = title; 132 133 // clear the 'detailsVisible' flag and reset the title of the 'showDetails' button 134 this._detailsVisible = false; 135 this._button[ZmErrorDialog.DETAIL_BUTTON].setText(this._showDetailsMsg); 136 137 // Set the content, enveloped 138 this._updateContent(); 139 }; 140 141 /** 142 * Sets/updates the content 143 */ 144 ZmErrorDialog.prototype._updateContent = 145 function() { 146 var data = { 147 message: this._msgStr, 148 detail: this._detailStr, 149 showDetails: this._detailsVisible 150 }; 151 var html = AjxTemplate.expand("zimbra.Widgets#ZmErrorDialogContent", data); 152 this.setSize(Dwt.CLEAR, this._detailsVisible ? "300" : Dwt.CLEAR); 153 DwtMessageDialog.prototype.setMessage.call(this, html, this._msgStyle, this._msgTitle); 154 }; 155 156 /** 157 * Pops-up the error dialog. 158 * 159 * @param {Object} loc the desired location 160 * @param {Boolean} hideReportButton if <code>true</code>, do not show "Send Error Report" button 161 * 162 */ 163 ZmErrorDialog.prototype.popup = 164 function(loc, hideReportButton) { 165 if (hideReportButton) { 166 this.setButtonVisible(ZmErrorDialog.REPORT_BUTTON, false); 167 } 168 DwtMessageDialog.prototype.popup.call(this, loc); 169 }; 170 171 /** 172 * Pops-down the dialog. 173 * 174 */ 175 ZmErrorDialog.prototype.popdown = 176 function() { 177 DwtMessageDialog.prototype.popdown.call(this); 178 179 // reset dialog 180 this.setSize(Dwt.CLEAR, Dwt.CLEAR); 181 this.setButtonVisible(ZmErrorDialog.REPORT_BUTTON, true); 182 }; 183 184 // 185 // Protected methods 186 // 187 /** 188 * @private 189 */ 190 ZmErrorDialog.prototype._getNavigatorInfo = 191 function() { 192 var strNav = []; 193 var idx = 0; 194 195 // Add the url 196 strNav[idx++] = "\n\n"; 197 strNav[idx++] = "href: "; 198 strNav[idx++] = location.href; 199 strNav[idx++] = "\n"; 200 201 for (var i in navigator) { 202 // Skip functions 203 if(typeof navigator[i] == "function") {continue;} 204 if(typeof navigator[i] == "unknown") {continue;} // IE7 205 if(AjxEnv.isIE && i === "mimeTypes") {continue;} 206 strNav[idx++] = i + ": " + navigator[i] + "\n"; 207 } 208 return strNav.join(""); 209 }; 210 211 /** 212 * @private 213 */ 214 ZmErrorDialog.prototype._getSubjectPrefix = 215 function() { 216 var strSubj = []; 217 var idx = 0; 218 219 strSubj[idx++] = "ER: "; 220 221 if (AjxEnv.isIE) strSubj[idx++] = "IE "; 222 else if (AjxEnv.isFirefox) strSubj[idx++] = "FF "; 223 else if (AjxEnv.isMozilla) strSubj[idx++] = "MOZ "; 224 else if (AjxEnv.isSafari) strSubj[idx++] = "SAF "; 225 else if (AjxEnv.isOpera) strSubj[idx++] = "OPE "; 226 else strSubj[idx++] = "UKN "; 227 228 if (AjxEnv.isWindows) strSubj[idx++] = "WIN "; 229 else if (AjxEnv.isLinux) strSubj[idx++] = "LNX "; 230 else if (AjxEnv.isMac) strSubj[idx++] = "MAC "; 231 else strSubj[idx++] = "UNK "; 232 233 strSubj[idx++] = appCtxt.get(ZmSetting.CLIENT_VERSION) + " "; 234 return strSubj.join(""); 235 }; 236 237 /** 238 * @private 239 */ 240 ZmErrorDialog.prototype._getUserPrefs = 241 function() { 242 var currSearch = appCtxt.getCurrentSearch(); 243 var strPrefs = []; 244 var idx = 0; 245 246 // Add username and current search 247 strPrefs[idx++] = "\n\n"; 248 strPrefs[idx++] = "username: "; 249 strPrefs[idx++] = appCtxt.get(ZmSetting.USERNAME); 250 strPrefs[idx++] = "\n"; 251 if (currSearch) { 252 strPrefs[idx++] = "currentSearch: "; 253 strPrefs[idx++] = currSearch.query; 254 strPrefs[idx++] = "\n"; 255 } 256 for (var i in ZmSetting.INIT) { 257 if (ZmSetting.INIT[i][0]) { 258 strPrefs[idx++] = ZmSetting.INIT[i][0]; 259 strPrefs[idx++] = ": "; 260 strPrefs[idx++] = ("" + ZmSetting.INIT[i][3]); 261 strPrefs[idx++] = "\n"; 262 } 263 } 264 return strPrefs.join(""); 265 }; 266 267 // Callbacks 268 269 /** 270 * @private 271 */ 272 ZmErrorDialog.prototype._reportCallback = 273 function() { 274 this._iframe = document.createElement("iframe"); 275 this._iframe.style.width = this._iframe.style.height = 0; 276 this._iframe.style.visibility = "hidden"; 277 278 var contentDiv = this._getContentDiv(); 279 contentDiv.appendChild(this._iframe); 280 281 var strPrefs = this._getUserPrefs(); 282 var formId = Dwt.getNextId(); 283 284 // generate html form for submission via POST 285 var html = []; 286 var idx = 0; 287 var subject = this._subjPfx + this._detailStr.substring(0,40); 288 var scheme = (location.protocol == 'https:') ? "https:" : "http:"; 289 html[idx++] = "<html><head></head><body><form id='"; 290 html[idx++] = formId; 291 html[idx++] = "' method='POST' action='"; 292 html[idx++] = scheme; 293 html[idx++] = appCtxt.get(ZmSetting.ERROR_REPORT_URL) || ZmErrorDialog.DEFAULT_REPORT_URL; 294 html[idx++] = "'>"; 295 html[idx++] = "<textarea name='details'>"; 296 html[idx++] = this._detailStr; 297 html[idx++] = "version - "; 298 html[idx++] = appCtxt.get(ZmSetting.CLIENT_VERSION); 299 html[idx++] = "\n"; 300 html[idx++] = "release - "; 301 html[idx++] = appCtxt.get(ZmSetting.CLIENT_RELEASE); 302 html[idx++] = "\n"; 303 html[idx++] = "date - "; 304 html[idx++] = appCtxt.get(ZmSetting.CLIENT_DATETIME); 305 html[idx++] = "</textarea><textarea name='navigator'>"; 306 html[idx++] = this._strNav; 307 html[idx++] = "</textarea><textarea name='prefs'>"; 308 html[idx++] = strPrefs; 309 html[idx++] = "</textarea><textarea name='subject'>"; 310 html[idx++] = subject; 311 html[idx++] = "</textarea></form></body></html>"; 312 313 var idoc = Dwt.getIframeDoc(this._iframe); 314 idoc.open(); 315 idoc.write(html.join("")); 316 idoc.close(); 317 318 // submit the form! 319 var form = idoc.getElementById(formId); 320 if (form) { 321 form.submit(); 322 appCtxt.setStatusMsg(ZmMsg.errorReportSent); 323 } 324 325 this.popdown(); 326 }; 327 328 /** 329 * Displays the detail text 330 */ 331 ZmErrorDialog.prototype.showDetail = 332 function() { 333 this._detailsVisible = !this._detailsVisible; 334 this._updateContent(); 335 this._button[ZmErrorDialog.DETAIL_BUTTON].setText(this._detailsVisible ? this._hideDetailsMsg : this._showDetailsMsg); 336 }; 337