Commit 4e1b54b2f08f8c4b7d9624a20a9616e19e3e78ef
- Diff rendering mode:
- inline
- side by side
email/email-mark-read-unread-mods.patch
(40 / 3505)
|   | |||
| 1 | INTRODUCTION | ||
| 2 | This patch modifies how messages are marked as read or unread in the | ||
| 3 | email application. | ||
| 1 | This patch modifies how messages are marked as read or unread in the email application. | ||
| 4 | 2 | ||
| 5 | WEBOS VERSION COMPATABILITY | ||
| 6 | This patch is designed and tested for webOS version 1.2.1 only. | ||
| 3 | This patch includes the following changes: | ||
| 4 | 1) Messages are NOT marked as read when they are opened from the message list card (by default, this is what happens, which may not be useful if you just want to *look* at a message but don't want to have it be marked as read) | ||
| 7 | 5 | ||
| 8 | DESCRIPTION | ||
| 9 | This patch makes the following changes: | ||
| 10 | 1) Messages are NOT marked as read when they are opened from the message | ||
| 11 | list card. Normally, this is what happens, which may not be useful if you | ||
| 12 | just want to review a message but don't want to have it be marked as read. | ||
| 6 | 2) Updates the "Mark as Read"/"Mark as Unread" menu item label and function to work based the read/unread state of the message instead of defaulting to "Mark as Unread" | ||
| 13 | 7 | ||
| 14 | 2) The "Mark as Read"/"Mark as Unread" menu item is properly coded to | ||
| 15 | set the label based on the read/unread state of the message. Because of | ||
| 16 | the default of marking a message as read when it is opened, the menu item | ||
| 17 | was hard-coded to always display as "Mark as Unread". Per #1 above, if | ||
| 18 | messages are not being marked as read when they are opened, this change | ||
| 19 | is needed to ensure the menu renders correctly. | ||
| 20 | |||
| 21 | 3) The message is marked as read when any of the following actions | ||
| 22 | happen: | ||
| 23 | a) message is forwarded | ||
| 24 | b) message is replied to (regular reply or reply-all) | ||
| 25 | c) message is deleted | ||
| 8 | 3) The message is marked as read when the message is forwarded, replied to, or deleted. | ||
| 26 | 9 | Index: /usr/palm/applications/com.palm.app.email/app/controllers/message-assistant.js | |
| 27 | 10 | =================================================================== | |
| 28 | 11 | --- .orig/usr/palm/applications/com.palm.app.email/app/controllers/message-assistant.js | |
| 29 | 12 | +++ /usr/palm/applications/com.palm.app.email/app/controllers/message-assistant.js | |
| 30 | @@ -1,1741 +1,1756 @@ | ||
| 31 | -/* Copyright 2009 Palm, Inc. All rights reserved. */ | ||
| 32 | - | ||
| 33 | -var MessageAssistant = Class.create({ | ||
| 34 | - initialize : function(targetEmail, folderId, focusStage, detailsObj) { | ||
| 35 | - this.data = { id: targetEmail, senderDetails:{} }; // data.id | ||
| 36 | - // This data is used to pre-render info in case the mailservice isn't able to respond quickly enough | ||
| 37 | - if (detailsObj) { | ||
| 38 | - this.data.prerenderData = true; | ||
| 39 | - this.data.displayName = detailsObj.displayName; | ||
| 40 | - this.data.summary = detailsObj.summary; | ||
| 41 | - this.data.timeStamp = detailsObj.timeStamp; | ||
| 42 | - this.data.flags = detailsObj.flags; | ||
| 43 | - this.data.priority = detailsObj.priority; | ||
| 44 | - } | ||
| 45 | - this.folderId = folderId; | ||
| 46 | - this.account = {}; | ||
| 47 | - this.gotFirstResponse = false; | ||
| 48 | - this.bodyLeftOffset = 0; | ||
| 49 | - this.transition = null; | ||
| 50 | - this.waitingForMessageBodyTimeout = undefined; | ||
| 51 | - this.attachmentDLProgress = { | ||
| 52 | - lastUpdate:0, | ||
| 53 | - progress:{}, | ||
| 54 | - subs:{}, | ||
| 55 | - clearSubscription: function(id) { | ||
| 56 | - try { | ||
| 57 | - this.subs[id].cancel(); | ||
| 58 | - delete (this.subs[id]); | ||
| 59 | - delete (this.progress[id]); | ||
| 60 | - } catch (e) { | ||
| 61 | - Mojo.Log.logException(e, "clearSubscription"); | ||
| 62 | - } | ||
| 63 | - } | ||
| 64 | - }; | ||
| 65 | - | ||
| 66 | - this.boundShowHideRecipients = this.showHideRecipients.bind(this); | ||
| 67 | - this.boundGotoNextEmailNewer = this.gotoNextEmail.bind(this, 'newer'); | ||
| 68 | - this.boundGotoNextEmailOlder = this.gotoNextEmail.bind(this, 'older'); | ||
| 69 | - this.boundHandleInviteResponseAccept = this.handleInviteResponse.bind(this, 'accept'); | ||
| 70 | - this.boundHandleInviteResponseTentative = this.handleInviteResponse.bind(this, 'tentative'); | ||
| 71 | - this.boundHandleInviteResponseDecline = this.handleInviteResponse.bind(this, 'decline'); | ||
| 72 | - this.boundHandleInviteResponseRemove = this.handleInviteResponse.bind(this, 'remove'); | ||
| 73 | - this.boundHandleLinkClicked = this.handleLinkClicked.bind(this); | ||
| 74 | - this.boundHandleInlineImageSaved = this.handleInlineImageSaved.bind(this); | ||
| 75 | - this.boundHandleWebViewSingleTap = this.handleWebViewSingleTap.bind(this); | ||
| 76 | - | ||
| 77 | - if (focusStage === true) { | ||
| 78 | - this.focusStageTimer = this.focusEmailStage.bind(this).delay(0.6); | ||
| 79 | - } | ||
| 80 | - }, | ||
| 81 | - | ||
| 82 | - addAsScrollListener: function(event) { | ||
| 83 | - event.scroller.addListener(this); | ||
| 84 | - }, | ||
| 85 | - | ||
| 86 | - moved: function() { | ||
| 87 | - var scrollOffset = this.messageTarget.viewportOffset(); | ||
| 88 | - if (this.bodyLeftOffset === scrollOffset.left) { | ||
| 89 | - return; | ||
| 90 | - } else if (this.webview !== undefined) { | ||
| 91 | - this.bodyLeftOffset = scrollOffset.left; | ||
| 92 | - // Get the width of the browseradapter since that should tell the truth about its width | ||
| 93 | - var webviewWidth = this.webview.down().getWidth(); | ||
| 94 | - //console.log("offsets: ov x=" + scrollOffset.left + ", w=" + this.emailHeaderBlock.getWidth() + ", wh=" + webviewWidth); | ||
| 95 | - | ||
| 96 | - if (scrollOffset.left > 0) { | ||
| 97 | - scrollOffset.left = 0; | ||
| 98 | - } else { | ||
| 99 | - var rightExtent = (this.emailHeaderBlock.getWidth() - webviewWidth); | ||
| 100 | - if (scrollOffset.left < rightExtent) { | ||
| 101 | - scrollOffset.left = rightExtent; | ||
| 102 | - } | ||
| 103 | - } | ||
| 104 | - | ||
| 105 | - // move the header block & the attached pictures block so they appear to not scroll horizontally | ||
| 106 | - var leftOffset = -scrollOffset.left + 'px'; | ||
| 107 | - this.emailHeaderBlock.setStyle({ 'left': leftOffset }); | ||
| 108 | - this.emailPicturesBlock.setStyle({ 'left': leftOffset }); | ||
| 109 | - } | ||
| 110 | - }, | ||
| 111 | - | ||
| 112 | - displayContactAvatarAndPresence: function(baseId, storageId, resp) { | ||
| 113 | - var nameId = baseId + "-name"; | ||
| 114 | - var avatarId = baseId + "-photo"; | ||
| 115 | - var presenceId = baseId + "-presence"; | ||
| 116 | - | ||
| 117 | - // If this person isn't in contact, give him ID=0. This is done in case the | ||
| 118 | - // contact was deleted, in which case the old settings need to be cleared. | ||
| 119 | - if (!resp.record) { | ||
| 120 | - resp.record = { id:0 }; | ||
| 121 | - } | ||
| 122 | - | ||
| 123 | - if (baseId === "email-sender") { | ||
| 124 | - this.data.fromID = resp.record.id; | ||
| 125 | - | ||
| 126 | -//<Reminder Info> | ||
| 127 | - if (resp.record && resp.record.reminder) { | ||
| 128 | - if (this.contactReminder === undefined) { | ||
| 129 | - this.contactReminder = new ContactReminder(); | ||
| 130 | - } | ||
| 131 | - this.contactReminder.displayReminder(resp); | ||
| 132 | - } | ||
| 133 | - } else { | ||
| 134 | - this.controller.get(storageId).writeAttribute('contactid', resp.record.id); | ||
| 135 | - } | ||
| 136 | - | ||
| 137 | - var nameElem = this.controller.get(nameId); | ||
| 138 | - if (resp.record.displayText) { | ||
| 139 | - nameElem.update(resp.record.displayText); | ||
| 140 | - } else if (resp.record.firstName && resp.record.lastName) { | ||
| 141 | - nameElem.update(resp.record.firstName + " " + resp.record.lastName); | ||
| 142 | - } else if (resp.record.firstName) { | ||
| 143 | - nameElem.update(resp.record.firstName); | ||
| 144 | - } else if (resp.record.lastName) { | ||
| 145 | - nameElem.update(resp.record.lastName); | ||
| 146 | - } | ||
| 147 | - | ||
| 148 | - if (resp.record.pictureLocSquare) { | ||
| 149 | - Mojo.Log.info("Displaying sender's picture ", resp.record.pictureLocSquare); | ||
| 150 | - var imgElem = this.controller.get(avatarId); | ||
| 151 | - imgElem.src = "file://" + resp.record.pictureLocSquare; | ||
| 152 | - var imgFrame = imgElem.up('.from-photo'); | ||
| 153 | - if (imgFrame !== undefined) { | ||
| 154 | - imgFrame.show(); | ||
| 155 | - } | ||
| 156 | - imgElem.up().up().up().addClassName("has-avatar-icon"); | ||
| 157 | - } | ||
| 158 | - | ||
| 159 | - if (resp.record) { | ||
| 160 | - if (resp.record.imAvailability !== undefined && | ||
| 161 | - resp.record.imAvailability !== null && | ||
| 162 | - resp.record.imAvailability !== IMName.NO_PRESENCE) { | ||
| 163 | - Mojo.Log.info("imAvailability = ", resp.record.imAvailability); | ||
| 164 | - var imPresence; | ||
| 165 | - switch (resp.record.imAvailability) { | ||
| 166 | - case IMName.BUSY: | ||
| 167 | - imPresence = 'status-busy'; | ||
| 168 | - break; | ||
| 169 | - case IMName.IDLE: | ||
| 170 | - imPresence = 'status-idle'; | ||
| 171 | - break; | ||
| 172 | - case IMName.ONLINE: | ||
| 173 | - imPresence = 'status-available'; | ||
| 174 | - break; | ||
| 175 | - default: | ||
| 176 | - imPresence = 'status-offline'; | ||
| 177 | - } | ||
| 178 | - var imgElem = this.controller.get(presenceId); | ||
| 179 | - imgElem.addClassName(imPresence); | ||
| 180 | - imgElem.show(); | ||
| 181 | - } | ||
| 182 | - } | ||
| 183 | - }, | ||
| 184 | - | ||
| 185 | - folderAndAccountDetails: function(resp) { | ||
| 186 | - // this gives us the following properties folder, account, login, protocol: EAS|IMAP|POP3} | ||
| 187 | - this.account = resp; | ||
| 188 | - // Add the email id to the account info because it will be used by the moveto scene | ||
| 189 | - this.account.emailId = this.data.id; | ||
| 190 | - var assistant = Mojo.Controller.getAppController().assistant; | ||
| 191 | - assistant.notificationAssistant.clear(resp.account, resp.folder, this.data.id); | ||
| 192 | - assistant.clearDebounce('m'+this.data.id); | ||
| 193 | - }, | ||
| 194 | - | ||
| 195 | - updateRecipientStatus: function() { | ||
| 196 | - EmailRecipient.getDetails(this.controller, this.data.senderDetails.address, this.displayContactAvatarAndPresence.bind(this, 'email-sender', null)); | ||
| 197 | - | ||
| 198 | - if (this.data.onlyRecipients !== undefined) { | ||
| 199 | - var theThis = this; | ||
| 200 | - this.data.onlyRecipients.each(function(r) { | ||
| 201 | - EmailRecipient.getDetails(theThis.controller, r.address, theThis.displayContactAvatarAndPresence.bind(theThis, 'recip-'+r.id, r.id)); | ||
| 202 | - }); | ||
| 203 | - } | ||
| 204 | - }, | ||
| 205 | - | ||
| 206 | - handleSenderTap: function(event) { | ||
| 207 | - this.showSenderContactDetails(event); | ||
| 208 | - }, | ||
| 209 | - | ||
| 210 | - showSenderContactDetails: function(event) { | ||
| 211 | - if (this.data.fromID) { | ||
| 212 | - EmailRecipient.launchContactDetails(this.controller, this.data.fromID); | ||
| 213 | - } else { | ||
| 214 | - var displayName = this.data.displayName; | ||
| 215 | - // if the display name is the email address it isn't really the person's name | ||
| 216 | - if (displayName === this.data.senderDetails.address) { | ||
| 217 | - displayName = ""; | ||
| 218 | - } | ||
| 219 | - EmailRecipient.addToContacts(this.controller, this.data.senderDetails.address, displayName); | ||
| 220 | - } | ||
| 221 | - }, | ||
| 222 | - | ||
| 223 | - handleRecipientListSelect: function(event) { | ||
| 224 | - var targetRow = this.controller.get(event.target); | ||
| 225 | - if (!targetRow.hasClassName('email-recipient')) { | ||
| 226 | - targetRow = targetRow.up('div.email-recipient'); | ||
| 227 | - } | ||
| 228 | - | ||
| 229 | - if (targetRow) { | ||
| 230 | - var contactId = targetRow.readAttribute('contactid'); | ||
| 231 | - if (contactId && contactId > 0) { | ||
| 232 | - EmailRecipient.launchContactDetails(this.controller, contactId); | ||
| 233 | - } else { | ||
| 234 | - var address = targetRow.readAttribute('address'); | ||
| 235 | - var displayName = targetRow.readAttribute('displayname'); | ||
| 236 | - displayName = displayName.escapeHTML(); | ||
| 237 | - EmailRecipient.addToContacts(this.controller, address, displayName); | ||
| 238 | - } | ||
| 239 | - } | ||
| 240 | - }, | ||
| 241 | - | ||
| 242 | - showHideRecipients: function(event) { | ||
| 243 | - this.recipsDrawer.element.mojo.setOpenState(!this.recipsDrawer.element.mojo.getOpenState()); | ||
| 244 | - this.controller.get('email_recipients_compressed_list').toggle(); | ||
| 245 | - this.controller.get('email_recipients_compressed_count').toggle(); | ||
| 246 | - }, | ||
| 247 | - | ||
| 248 | - messageDetailsUpdated: function(resp) { | ||
| 249 | - if (this.gotFirstResponse === false) { | ||
| 250 | - this.gotFirstResponse = true; | ||
| 251 | - this.renderMessage(resp); | ||
| 252 | - } else { | ||
| 253 | - Mojo.Log.info("renderMessage: waiting for message body. isFullyLoaded=", resp.isFullyLoaded); | ||
| 254 | - if (resp.isFullyLoaded == "true") { | ||
| 255 | - if (this.waitingForMessageBodyTimeout !== undefined) { | ||
| 256 | - clearTimeout(this.waitingForMessageBodyTimeout); | ||
| 257 | - this.waitingForMessageBodyTimeout = undefined; | ||
| 258 | - } | ||
| 259 | - // Add the email body to the stored data model | ||
| 260 | - this.data.textURI = resp.textURI; | ||
| 261 | - this.data.text = resp.text; | ||
| 262 | - this.renderMessageBody(resp); | ||
| 263 | - } | ||
| 264 | - | ||
| 265 | - // POP doesn't know it has attachments until it has downloaded the full envelope | ||
| 266 | - // so use the new attachment list if one there doesn't already exist | ||
| 267 | - if ((!this.data.attachments || this.data.attachments.length === 0) && | ||
| 268 | - resp.attachments && EmailFlags.hasAttachment(resp.flags)) { | ||
| 269 | - this.data.attachments = resp.attachments; | ||
| 270 | - this.renderMessageAttachments(resp.attachments); | ||
| 271 | - } | ||
| 272 | - } | ||
| 273 | - }, | ||
| 274 | - | ||
| 275 | - // This is a special function that is only called when the scene is first launched | ||
| 276 | - // and activate() occurs before the mailservice has time to respond with the full | ||
| 277 | - // email data. | ||
| 278 | - prerenderMessage: function(resp) { | ||
| 279 | - this.data.prerenderData = false; // only want to prerender email once | ||
| 280 | - Mojo.Log.info("prerenderMessage ", resp.id); | ||
| 281 | - | ||
| 282 | - if ((resp.flags & EmailFlags.flaggedBit) !== 0) { | ||
| 283 | - resp.flagged = "starred"; | ||
| 284 | - } | ||
| 285 | - | ||
| 286 | - //convert the timestamp into a Date | ||
| 287 | - var theDate = new Date(parseInt(resp.timeStamp)); | ||
| 288 | - resp.formattedDate = Mojo.Format.formatDate(theDate, {date:'medium', time:'short'}); | ||
| 289 | - resp.meridiem = ""; | ||
| 290 | - | ||
| 291 | - var content = Mojo.View.render({template: 'message/message_from', object:resp}); | ||
| 292 | - this.controller.get('email_from').update(content); | ||
| 293 | - //subject | ||
| 294 | - resp.priority = Email.getPriorityClass(resp.priority); | ||
| 295 | - content = Mojo.View.render({template: 'message/message_subject', object: resp}); | ||
| 296 | - this.controller.get('email_subject').update(content); | ||
| 297 | - }, | ||
| 298 | - | ||
| 299 | - renderMessage: function(resp) { | ||
| 300 | - var content; | ||
| 301 | - Mojo.Log.info("renderMessage ", resp.id); | ||
| 302 | - this.data = resp; | ||
| 303 | - | ||
| 304 | - // Set the "read" flag if need be | ||
| 305 | - if (!EmailFlags.isRead(resp.flags)) { | ||
| 306 | - Email.setRead(resp.id, true); | ||
| 307 | - } | ||
| 308 | - | ||
| 309 | - // Very first thing to do with recipients is fix them up for the address picker. | ||
| 310 | - EmailRecipient.addAddressPickerFields(resp.recipients); | ||
| 311 | - | ||
| 312 | - var attachments = resp.attachments; | ||
| 313 | - | ||
| 314 | - if (resp.displayName) { | ||
| 315 | - resp.displayName = resp.displayName.escapeHTML(); | ||
| 316 | - } | ||
| 317 | - | ||
| 318 | - if (this.data.summary == null || this.data.summary.length === 0) { | ||
| 319 | - this.data.summary = $L("Untitled message"); | ||
| 320 | - } else { | ||
| 321 | - resp.summary = resp.summary.escapeHTML(); | ||
| 322 | - } | ||
| 323 | - | ||
| 324 | - if ((resp.flags & EmailFlags.flaggedBit) !== 0) { | ||
| 325 | - resp.flagged = "starred"; | ||
| 326 | - this.markSetFlagMenuItem.label = MessageAssistant.kAppMenuClearFlag; | ||
| 327 | - } else { | ||
| 328 | - this.markSetFlagMenuItem.label = MessageAssistant.kAppMenuSetFlag; | ||
| 329 | - } | ||
| 330 | - | ||
| 331 | - //text -- if it is fully loaded then render it (need to check for string "true" since that's what's coming in json). | ||
| 332 | - if (this.data.isFullyLoaded == "true") { | ||
| 333 | - this.renderMessageBody(this.data); | ||
| 334 | - } else { | ||
| 335 | - this.waitForMessageBody(); | ||
| 336 | - } | ||
| 337 | - | ||
| 338 | - //convert the timestamp into a Date | ||
| 339 | - //February 15, 2008 - 12:57 PM | ||
| 340 | - var theDate = new Date(parseInt(resp.timeStamp)); | ||
| 341 | - resp.formattedDate = Mojo.Format.formatDate(theDate, {date:'medium', time:'short'}); | ||
| 342 | - resp.meridiem = ""; //theDate.toString($L('t')); | ||
| 343 | - | ||
| 344 | - content = Mojo.View.render({template: 'message/message_from', object:resp}); | ||
| 345 | - this.controller.get('email_from').update(content); | ||
| 346 | - //subject | ||
| 347 | - resp.priority = Email.getPriorityClass(resp.priority); | ||
| 348 | - content = Mojo.View.render({template: 'message/message_subject', object: resp}); | ||
| 349 | - this.controller.get('email_subject').update(content); | ||
| 350 | - | ||
| 351 | - this.controller.get('previous_email').observe(Mojo.Event.tap, this.boundGotoNextEmailNewer); | ||
| 352 | - this.controller.get('next_email').observe(Mojo.Event.tap, this.boundGotoNextEmailOlder); | ||
| 353 | - | ||
| 354 | - //recipients | ||
| 355 | - this.renderMessageRecipients(resp); | ||
| 356 | - | ||
| 357 | - if (EmailFlags.isMeetingRequest(resp.flags)) { | ||
| 358 | - var invite = new Object(); | ||
| 359 | - if (resp.whenStart) { | ||
| 360 | - var startDate = new Date(parseInt(resp.whenStart)); | ||
| 361 | - var dateFormat = $L('EEE, MMM d'); | ||
| 362 | - var whenObject = { | ||
| 363 | - date: Mojo.Format.formatDate(startDate, {date:dateFormat}), | ||
| 364 | - startTime: Mojo.Format.formatDate(startDate, {time:'short'}), | ||
| 365 | - endTime: Mojo.Format.formatDate(new Date(parseInt(resp.whenEnd)), {time:'short'}) | ||
| 366 | - }; | ||
| 367 | - invite.when = $L("#{date}, #{startTime} - #{endTime}").interpolate(whenObject); | ||
| 368 | - } else { | ||
| 369 | - // Service used to format the date. That doesn't work for too many reasons | ||
| 370 | - invite.when = $L("#{when}").interpolate(resp); //TODO parse this and put in local date format | ||
| 371 | - } | ||
| 372 | - if (resp.busyStatus === 0) { | ||
| 373 | - // Maybe change the style here | ||
| 374 | - invite.conflict = $L("Conflicts with another event"); | ||
| 375 | - } | ||
| 376 | - invite.where = $L("#{where}").interpolate(resp).escapeHTML(); | ||
| 377 | - | ||
| 378 | - content = Mojo.View.render({template: 'message/meeting_invitation', object: invite}); | ||
| 379 | - this.controller.get('email-readview-invitations').update(content); | ||
| 380 | - | ||
| 381 | - this.controller.get('invite-accept').observe(Mojo.Event.tap, this.boundHandleInviteResponseAccept); | ||
| 382 | - this.controller.get('invite-tentative').observe(Mojo.Event.tap, this.boundHandleInviteResponseTentative); | ||
| 383 | - this.controller.get('invite-decline').observe(Mojo.Event.tap, this.boundHandleInviteResponseDecline); | ||
| 384 | - } | ||
| 385 | - else if (EmailFlags.isMeetingCancel(resp.flags)) { | ||
| 386 | - content = Mojo.View.render({template: 'message/meeting_cancellation', object: {}}); | ||
| 387 | - this.controller.get('email-readview-invitations').update(content); | ||
| 388 | - this.controller.get('invite-remove').observe(Mojo.Event.tap, this.boundHandleInviteResponseRemove); | ||
| 389 | - } | ||
| 390 | - else { | ||
| 391 | - this.controller.get('email-readview-invitations').update(""); | ||
| 392 | - } | ||
| 393 | - | ||
| 394 | - // Attachments - some may be in the HTML body, so only show the attachments area if there | ||
| 395 | - // is something in the attachments array | ||
| 396 | - if (attachments && EmailFlags.hasAttachment(this.data.flags)) { | ||
| 397 | - this.renderMessageAttachments(attachments); | ||
| 398 | - } else { | ||
| 399 | - // If no attachments, make sure old UI is cleaned out. | ||
| 400 | - this.controller.get('email-readview-attachments-block').hide(); | ||
| 401 | - this.emailPicturesBlock.update(""); | ||
| 402 | - } | ||
| 403 | - | ||
| 404 | - // Ensure the whiteness is at least tall enough to fill the screen. | ||
| 405 | - var contentContainer = this.controller.get('email-readview-content-container'); | ||
| 406 | - var po = contentContainer.positionedOffset(); | ||
| 407 | - var minHeight = (this.controller.window.innerHeight - po.top) + 'px'; | ||
| 408 | - contentContainer.setStyle({'min-height':minHeight}) | ||
| 409 | - | ||
| 410 | - // Got the message details so say we're ready to render | ||
| 411 | - if (this.delayActivate === true) { | ||
| 412 | - this.delayActivate = false; | ||
| 413 | - if (this.readyToActivateCallback !== undefined) { | ||
| 414 | - this.readyToActivateCallback(); | ||
| 415 | - this.readyToActivateCallback = undefined; | ||
| 416 | - } | ||
| 417 | - } | ||
| 418 | - | ||
| 419 | - // Get details about the next and previous emails to know where the user can navigate. | ||
| 420 | - // NOTE: this needs to be after message_subject is rendered | ||
| 421 | - this.controller.serviceRequest(Email.identifier, { | ||
| 422 | - method: 'getNextMessages', | ||
| 423 | - parameters: {'message':this.data.id, 'folder': this.folderId }, | ||
| 424 | - onSuccess: this.handleNextMessagesResponse.bind(this), | ||
| 425 | - onFailure: function(response) { Mojo.Log.error("getNextMessages failed "+Object.toJSON(response)); } | ||
| 426 | - }); | ||
| 427 | - | ||
| 428 | - if (this.transition !== null) { | ||
| 429 | - this.transition.run(); | ||
| 430 | - this.transition.cleanup(); | ||
| 431 | - this.transition = null; | ||
| 432 | - } | ||
| 433 | - }, | ||
| 434 | - | ||
| 435 | - renderMessageRecipients: function(resp) { | ||
| 436 | - var recips = resp.recipients; | ||
| 437 | - this.data.onlyRecipients = []; | ||
| 438 | - this.data.senderDetails = {}; | ||
| 439 | - var content = null; | ||
| 440 | - if (recips) { | ||
| 441 | - var recipTypes; | ||
| 442 | - if (EmailFlags.isMeetingType(resp.flags)) { | ||
| 443 | - recipTypes = [ $L("From"), $L("Required"), $L("Optional"), $L("Bcc"), $L("From") ]; | ||
| 444 | - } else { | ||
| 445 | - recipTypes = [ $L("From"), $L("To"), $L("Cc"), $L("Bcc"), $L("From") ]; | ||
| 446 | - } | ||
| 447 | - | ||
| 448 | - var theThis = this; | ||
| 449 | - var prevRecp = {}; // This is used to determine when to display To/Cc/Bcc divider | ||
| 450 | - recips.each(function(r) { | ||
| 451 | - if(recipTypes[r.role] !== undefined) { | ||
| 452 | - if (r.role === EmailRecipient.roleTo || r.role === EmailRecipient.roleCc || r.role === EmailRecipient.roleBcc) { | ||
| 453 | - r.roleStr = recipTypes[r.role]; | ||
| 454 | - if (r.role != prevRecp.role) { | ||
| 455 | - r.rowDisplayRole = "show"; | ||
| 456 | - r.hasDivider = "has-divider"; | ||
| 457 | - prevRecp.hideLast = "last"; | ||
| 458 | - } | ||
| 459 | - theThis.data.onlyRecipients.push(r); | ||
| 460 | - EmailRecipient.getDetails(theThis.controller, r.address, theThis.displayContactAvatarAndPresence.bind(theThis, 'recip-'+r.id, r.id)); | ||
| 461 | - prevRecp = r; | ||
| 462 | - } | ||
| 463 | - // roleReplyTo can overwrite the senderDetails because it takes precidence over roleFrom | ||
| 464 | - else if (r.role === EmailRecipient.roleReplyTo) { | ||
| 465 | - theThis.data.senderDetails = r; | ||
| 466 | - } | ||
| 467 | - // roleFrom should not overwrite the senderDetails because roleReplyTo takes precidence | ||
| 468 | - else if (r.role === EmailRecipient.roleFrom && theThis.data.senderDetails.address === undefined) { | ||
| 469 | - theThis.data.senderDetails = r; | ||
| 470 | - } | ||
| 471 | - } | ||
| 472 | - }); | ||
| 473 | - | ||
| 474 | - if (this.data.senderDetails.address !== undefined) { | ||
| 475 | - // Get the contact ID for the sender of the email | ||
| 476 | - EmailRecipient.getDetails(this.controller, this.data.senderDetails.address, this.displayContactAvatarAndPresence.bind(this, 'email-sender', null)); | ||
| 477 | - } | ||
| 478 | - | ||
| 479 | - if (this.data.onlyRecipients.length > 0) { | ||
| 480 | - var recipElem = this.controller.get('email_recipients'); | ||
| 481 | - content = Mojo.View.render({ | ||
| 482 | - collection: this.data.onlyRecipients, | ||
| 483 | - template: 'message/message_recips' | ||
| 484 | - }); | ||
| 485 | - recipElem.update(content); | ||
| 486 | - | ||
| 487 | - var recipsSummary = { count:0, to:[], cc:[], bcc:[] }; | ||
| 488 | - this.data.onlyRecipients.each(function(r) { | ||
| 489 | - if (r.role === EmailRecipient.roleTo) { | ||
| 490 | - recipsSummary.to.push(r.displayName); | ||
| 491 | - recipsSummary.count++; | ||
| 492 | - } else if (r.role === EmailRecipient.roleCc) { | ||
| 493 | - recipsSummary.cc.push(r.displayName); | ||
| 494 | - recipsSummary.count++; | ||
| 495 | - } else if (r.role === EmailRecipient.roleBcc) { | ||
| 496 | - recipsSummary.bcc.push(r.displayName); | ||
| 497 | - recipsSummary.count++; | ||
| 498 | - } | ||
| 499 | - }); | ||
| 500 | - | ||
| 501 | - if (recipsSummary.count > 0) { | ||
| 502 | - recipsSummary.displayTo = "none"; | ||
| 503 | - recipsSummary.displayCc = "none"; | ||
| 504 | - recipsSummary.displayBcc = "none"; | ||
| 505 | - if (recipsSummary.to.length > 0 && recipsSummary.cc.length > 0) { | ||
| 506 | - recipsSummary.displayTo = "inline"; | ||
| 507 | - recipsSummary.displayCc = "inline"; | ||
| 508 | - recipsSummary.toList = recipsSummary.to.join(', '); | ||
| 509 | - recipsSummary.ccList = recipsSummary.cc.join(', '); | ||
| 510 | - } else if (recipsSummary.to.length > 0) { | ||
| 511 | - recipsSummary.displayTo = "inline"; | ||
| 512 | - recipsSummary.toList = recipsSummary.to.join(', '); | ||
| 513 | - } else if (recipsSummary.cc.length > 0) { | ||
| 514 | - recipsSummary.displayCc = "inline"; | ||
| 515 | - recipsSummary.ccList = recipsSummary.cc.join(', '); | ||
| 516 | - } else if (recipsSummary.bcc.length > 0) { | ||
| 517 | - recipsSummary.displayBcc = "inline"; | ||
| 518 | - recipsSummary.bccList = recipsSummary.bcc.join(', '); | ||
| 519 | - } | ||
| 520 | - | ||
| 521 | - if (recipsSummary.count === 1) { | ||
| 522 | - recipsSummary.recipientCount = $L("1 recipient"); | ||
| 523 | - } else { | ||
| 524 | - recipsSummary.recipientCount = $L("#{count} recipients").interpolate(recipsSummary); | ||
| 525 | - } | ||
| 526 | - | ||
| 527 | - content = Mojo.View.render({template: 'message/message_recips_compressed', object: recipsSummary }); | ||
| 528 | - this.recipientController = this.controller.get('email_recipients_controller') | ||
| 529 | - this.recipientController.update(content); | ||
| 530 | - // Observe the row since that is the entire height and width of the tappable area | ||
| 531 | - this.recipientController.up(".palm-row").observe(Mojo.Event.tap, this.boundShowHideRecipients, true); | ||
| 532 | - } | ||
| 533 | - } | ||
| 534 | - } | ||
| 535 | - | ||
| 536 | - // If there were no recipients, then display the default "no recips" | ||
| 537 | - if (content === null) { | ||
| 538 | - Mojo.Log.info("displaying 'Only BCC recipients'"); | ||
| 539 | - var renderParams = { | ||
| 540 | - template: 'message/message_recips_compressed', | ||
| 541 | - object: {onlyBccRecipient: $L("Only BCC recipients"), displayTo: "none", displayCc: "none", displayBcc: "none" } | ||
| 542 | - }; | ||
| 543 | - this.controller.get('email_recipients_controller').update(Mojo.View.render(renderParams)); | ||
| 544 | - } | ||
| 545 | - }, | ||
| 546 | - | ||
| 547 | - processTextProperty: function(data) { | ||
| 548 | - // If it is an html email, it starts with "<!DOCTYPE" or "<html" some simple html tag | ||
| 549 | - if (!data.isHtml) { | ||
| 550 | - //console.log("******* NO MATCH *********") | ||
| 551 | - // Plain text needs to replace the carriage returns with html line-break tags | ||
| 552 | - data.text = data.text.escapeHTML().gsub("\n","<br>"); | ||
| 553 | - } else { | ||
| 554 | - //console.log("******* MATCH *********") | ||
| 555 | - data.text = data.text.stripScripts(); | ||
| 556 | - } | ||
| 557 | - }, | ||
| 558 | - | ||
| 559 | - renderMessageBody: function(data) { | ||
| 560 | - if (data.isFullyLoaded != "true") { | ||
| 561 | - Mojo.Log.error("renderMessageBody aborted because data.isFullyLoaded == ", data.isFullyLoaded) | ||
| 562 | - return; | ||
| 563 | - } | ||
| 564 | - | ||
| 565 | - this.hideNoBodyUI(); | ||
| 566 | - | ||
| 567 | - if (data.textURI && this.webview.mojo.openURL) { | ||
| 568 | - this.controller.get('email_text').hide(); | ||
| 569 | - | ||
| 570 | - try { | ||
| 571 | - Mojo.Log.breadcrumb("rendering URI " + data.textURI); | ||
| 572 | - this.webview.mojo.setEnableJavaScript(false); | ||
| 573 | - this.webview.mojo.openURL("file://" + data.textURI); | ||
| 574 | - } catch (e) { | ||
| 575 | - Mojo.Log.logException(e, 'renderMessageBody openUrl'); | ||
| 576 | - } | ||
| 577 | - | ||
| 578 | - // If the service didn't supply the text to use for replying to an email, request it now. | ||
| 579 | - if (!data.text) { | ||
| 580 | - var processTextProperty = this.processTextProperty; | ||
| 581 | - this.controller.serviceRequest(Message.identifier, { | ||
| 582 | - method: 'messageFileText', | ||
| 583 | - parameters: { 'textURI':data.textURI }, | ||
| 584 | - onSuccess: function(resp) { | ||
| 585 | - data.text = resp.text; | ||
| 586 | - processTextProperty(data); | ||
| 587 | - }, | ||
| 588 | - onFailure: function() { Mojo.Log.error("messageFileText failed for textURI", data.textURI) } | ||
| 589 | - }); | ||
| 590 | - } else { | ||
| 591 | - // Defer b/c this can be done after the email is rendered | ||
| 592 | - this.processTextProperty.defer(data); | ||
| 593 | - } | ||
| 594 | - } else { | ||
| 595 | - Mojo.Log.warn("WARNING: EMAIL using plain text"); | ||
| 596 | - var adapter = this.controller.get('email_body_text_outer'); | ||
| 597 | - if (adapter == null) { | ||
| 598 | - adapter = this.controller.get('email_body_text'); | ||
| 599 | - } | ||
| 600 | - adapter.hide(); | ||
| 601 | - var emailBody = this.controller.get('email_text'); | ||
| 602 | - // Strip out all scripts since they can do dangerous things | ||
| 603 | - data.text = data.text.stripScripts(); | ||
| 604 | - // Since this is plain text, need to replace the carriage returns with html line-break tags | ||
| 605 | - data.text = data.text.gsub("\n","<br>"); | ||
| 606 | - data.styles = "width:"+this.controller.window.innerWidth+"px;"; | ||
| 607 | - var content = Mojo.View.render({ | ||
| 608 | - template: 'message/message_text', | ||
| 609 | - object: data | ||
| 610 | - }); | ||
| 611 | - emailBody.update(content); | ||
| 612 | - emailBody.show(); | ||
| 613 | - } | ||
| 614 | - | ||
| 615 | - this.webview.mojo.focus(); | ||
| 616 | - }, | ||
| 617 | - | ||
| 618 | - renderMessageAttachments: function(attachments) { | ||
| 619 | - // Show the div containing the attachments. For multiple attachments, also | ||
| 620 | - // show the expand/collapse controller | ||
| 621 | - this.controller.get('email-readview-attachments-block').show(); | ||
| 622 | - | ||
| 623 | - var picturesList = []; | ||
| 624 | - var names = undefined; | ||
| 625 | - attachments.each(function(a) { | ||
| 626 | - a.displayName = a.displayName.escapeHTML(); | ||
| 627 | - if (names === undefined) { | ||
| 628 | - names = a.displayName.substring(0); // copy of the name | ||
| 629 | - } else { | ||
| 630 | - names += ", " + a.displayName; | ||
| 631 | - } | ||
| 632 | - // Icons | ||
| 633 | - Attachments.processFileObject(a); | ||
| 634 | - // Picture to be displayed | ||
| 635 | - if (a.iconType == "type-image") { | ||
| 636 | - var extension = a.extension.toLowerCase(); | ||
| 637 | - if (extension === ".jpg" || extension === ".jpeg" || extension === ".png") { | ||
| 638 | - a.fixeduri = "file:///var/luna/data/extractfs/" + a.uri + ":0:0:320:240:3"; | ||
| 639 | - } else { | ||
| 640 | - a.fixeduri = a.uri; | ||
| 641 | - } | ||
| 642 | - picturesList.push(a); | ||
| 643 | - } else { | ||
| 644 | - a.displayImage = "display:none"; | ||
| 645 | - } | ||
| 646 | - | ||
| 647 | - // Download % | ||
| 648 | - if (a.uri) { | ||
| 649 | - a.display = "display: none;"; | ||
| 650 | - a.download = ""; | ||
| 651 | - } else { | ||
| 652 | - a.download = "show-download-icon"; | ||
| 653 | - a.display = "display: none;"; | ||
| 654 | - } | ||
| 655 | - }); | ||
| 656 | - | ||
| 657 | - // Only show the special "this file and N others" if there's more than 1 attachment | ||
| 658 | - if (attachments.length > 1) { | ||
| 659 | - // Setup the attachment compressed view | ||
| 660 | - var content = Mojo.View.render({ | ||
| 661 | - object: { displayName:names, count:attachments.length }, | ||
| 662 | - template: 'message/message_attachments_compressed' | ||
| 663 | - }); | ||
| 664 | - this.attachmentsShowElem.update(content); | ||
| 665 | - } | ||
| 666 | - | ||
| 667 | - content = Mojo.View.render({ | ||
| 668 | - collection: attachments, | ||
| 669 | - template: 'message/message_attachments' | ||
| 670 | - }); | ||
| 671 | - this.controller.get('email-readview-attachments-list').update(content); | ||
| 672 | - | ||
| 673 | - // Attachment pictures | ||
| 674 | - if (picturesList.length > 0) { | ||
| 675 | - content = Mojo.View.render({ | ||
| 676 | - collection: picturesList, | ||
| 677 | - template: 'message/message_pictures' | ||
| 678 | - }); | ||
| 679 | - this.emailPicturesBlock.update(content); | ||
| 680 | - } else { | ||
| 681 | - this.emailPicturesBlock.update(""); | ||
| 682 | - } | ||
| 683 | - | ||
| 684 | - // Convert any downloaded audio attachments to AudioTag controls | ||
| 685 | - attachments.each(function(a) { | ||
| 686 | - if (a.uri !== undefined) { | ||
| 687 | - this.setupAudioTag(a); | ||
| 688 | - } | ||
| 689 | - }.bind(this)); | ||
| 690 | - | ||
| 691 | - // | ||
| 692 | - // Now that the contents of the list are ready, compute heights and setup the "drawer" | ||
| 693 | - // | ||
| 694 | - this.attachmentList = this.controller.get('attachlist-list1'); | ||
| 695 | - this.attachmentList.setStyle({height:'auto'}); // make sure the height below is the full height | ||
| 696 | - this.attachmentListHeight = parseInt(this.attachmentList.getHeight(), 10); | ||
| 697 | - | ||
| 698 | - // If the list contains only 1 item so it isn't considered as "shown" | ||
| 699 | - this.attachmentListShown = (attachments.length > 1); | ||
| 700 | - if (this.attachmentListShown) { | ||
| 701 | - // Initially hide the attachments list | ||
| 702 | - this.attachmentListShown = false; | ||
| 703 | - this.attachmentList.setStyle({'height':'46px'}); | ||
| 704 | - this.attachmentList.hide(); | ||
| 705 | - this.attachmentsShowElem.show(); | ||
| 706 | - } else { | ||
| 707 | - this.attachmentsShowElem.hide(); | ||
| 708 | - this.attachmentList.show(); | ||
| 709 | - } | ||
| 710 | - }, | ||
| 711 | - | ||
| 712 | - setupAudioTag: function(a) { | ||
| 713 | - var success = false; | ||
| 714 | - if (a.uri !== undefined && a.mimeType.startsWith("audio")) { | ||
| 715 | - var audioElement = this.controller.get("progress_" + a.id); | ||
| 716 | - try { | ||
| 717 | - audioElement.show(); | ||
| 718 | - var audioTag = AudioTag.extendElement(audioElement, this.controller, a.uri); | ||
| 719 | - audioTag.autoplay = false; | ||
| 720 | - this.controller.get("adetails_" + a.id).hide(); | ||
| 721 | - success = true; | ||
| 722 | - } catch (e) { | ||
| 723 | - audioElement.hide(); | ||
| 724 | - } | ||
| 725 | - } | ||
| 726 | - return success; | ||
| 727 | - }, | ||
| 728 | - | ||
| 729 | - waitForMessageBody: function() { | ||
| 730 | - // If the transport can't retrieve the message in a reasonable amount of time, error out | ||
| 731 | - this.waitingForMessageBodyTimeout = this.waitMessageError.bind(this).delay(45); | ||
| 732 | - this.showNoBodyUI(); | ||
| 733 | - }, | ||
| 734 | - | ||
| 735 | - waitMessageError: function(resp) { | ||
| 736 | - if (this.messageSubscription) { | ||
| 737 | - this.messageSubscription.cancel(); | ||
| 738 | - this.messageSubscription = null; | ||
| 739 | - } | ||
| 740 | - Mojo.Log.error("waitMessageError", Object.toJSON(resp)); | ||
| 741 | - | ||
| 742 | - // Waiting for message body means the message exists, but the body | ||
| 743 | - // isn't yet on device. If the error occured before even waiting for | ||
| 744 | - // the body, then popScene out to the previous scene because this | ||
| 745 | - // email doesn't even exists anymore. | ||
| 746 | - if (this.waitingForMessageBodyTimeout === undefined) { | ||
| 747 | - // This should only occur if the email ID doesn't exist so go back to the previous scene | ||
| 748 | - Mojo.Log.error("popping the message scene because message doesn't exists. ID=", this.data.id); | ||
| 749 | - this.controller.stageController.popScene(resp); | ||
| 750 | - } else { | ||
| 751 | - clearTimeout(this.waitingForMessageBodyTimeout); | ||
| 752 | - this.waitingForMessageBodyTimeout = undefined; | ||
| 753 | - this.hideNoBodyUI(); | ||
| 754 | - | ||
| 755 | - // Display error text | ||
| 756 | - this.plainTextBody.update(Mojo.View.render({template: 'message/failed_to_download_err', object:{}})); | ||
| 757 | - this.plainTextBody.show(); | ||
| 758 | - } | ||
| 759 | - }, | ||
| 760 | - | ||
| 761 | - showNoBodyUI: function() { | ||
| 762 | - var nobodyDiv = this.controller.get('email_no_body') | ||
| 763 | - nobodyDiv.show(); | ||
| 764 | - this.controller.instantiateChildWidgets(nobodyDiv); | ||
| 765 | - this.controller.get('email_no_body_spinner').mojo.start(); | ||
| 766 | - }, | ||
| 767 | - | ||
| 768 | - hideNoBodyUI: function() { | ||
| 769 | - this.controller.get('email_no_body_spinner').mojo.stop(); | ||
| 770 | - this.controller.get('email_no_body').hide(); | ||
| 771 | - }, | ||
| 772 | - | ||
| 773 | - handleToggleFavorites: function(event) { | ||
| 774 | - // Flip the flagged bit | ||
| 775 | - var value = true; | ||
| 776 | - this.data.flags = this.data.flags ^ EmailFlags.flaggedBit; | ||
| 777 | - if ((this.data.flags & EmailFlags.flaggedBit) == 0) { | ||
| 778 | - this.controller.get('email_favorite').removeClassName("starred"); | ||
| 779 | - this.data.flagged = ""; | ||
| 780 | - this.markSetFlagMenuItem.label = MessageAssistant.kAppMenuSetFlag; | ||
| 781 | - value = false; | ||
| 782 | - } else { | ||
| 783 | - this.controller.get('email_favorite').addClassName("starred"); | ||
| 784 | - this.data.flagged = "starred"; | ||
| 785 | - this.markSetFlagMenuItem.label = MessageAssistant.kAppMenuClearFlag; | ||
| 786 | - } | ||
| 787 | - //console.log("Setting flagged for " + this.data.id + " to " + value); | ||
| 788 | - Email.setFlagged(this.data.id, value); | ||
| 789 | - }, | ||
| 790 | - | ||
| 791 | - handleAttachmentTapped: function(event) { | ||
| 792 | - var targetRow = this.controller.get(event.target); | ||
| 793 | - var listDiv = targetRow; | ||
| 794 | - if (!listDiv.hasClassName('attachment-info')) { | ||
| 795 | - listDiv = listDiv.up('div.attachment-info'); | ||
| 796 | - } | ||
| 797 | - | ||
| 798 | - if (listDiv) { | ||
| 799 | - var attachmentUri = listDiv.getAttribute('x-uri'); | ||
| 800 | - var attachmentMimeType = listDiv.getAttribute('x-mimetype'); | ||
| 801 | - if (attachmentUri) { | ||
| 802 | - if (attachmentMimeType.startsWith("audio")) { | ||
| 803 | - // Do nothing because the AudioTag widget handles taps for audio files | ||
| 804 | - } else if (attachmentMimeType.startsWith("image")) { | ||
| 805 | - this.controller.stageController.pushScene('imageview', attachmentUri); | ||
| 806 | - } else { | ||
| 807 | - if (attachmentUri.startsWith("/")) { | ||
| 808 | - attachmentUri = "file://" + attachmentUri; | ||
| 809 | - } | ||
| 810 | - //Message.launchAttachment(this.controller, attachmentUri, this.error.bind(this)); | ||
| 811 | - Message.getResourceType(this.controller, attachmentUri, attachmentMimeType, this.gotResourceType.bind(this), this.useInternalResourceHandler.bind(this, attachmentMimeType)); | ||
| 812 | - } | ||
| 813 | - } else if (event.target.className === "download-cancel") { | ||
| 814 | - this.stopAttachmentDownload(listDiv.id); | ||
| 815 | - } else { | ||
| 816 | - // Stop the timeout | ||
| 817 | - if (this.hideTimeout) { | ||
| 818 | - clearTimeout(this.hideTimeout); | ||
| 819 | - this.hideTimeout = null; | ||
| 820 | - } | ||
| 821 | - this.startAttachmentDownload(listDiv.id); | ||
| 822 | - } | ||
| 823 | - } | ||
| 824 | - }, | ||
| 825 | - | ||
| 826 | - handleImageTapped: function(event) { | ||
| 827 | - var imgElem = this.controller.get(event.target.id); | ||
| 828 | - var uri = imgElem.getAttribute('x-uri'); | ||
| 829 | - this.controller.stageController.pushScene('imageview', uri); | ||
| 830 | - }, | ||
| 831 | - | ||
| 832 | - /* | ||
| 833 | - * Callback function for getResourceType | ||
| 834 | - */ | ||
| 835 | - gotResourceType: function(payload) { | ||
| 836 | - //Check if this is launchable | ||
| 837 | - if(payload.returnValue && payload.appIdByExtension) { | ||
| 838 | - Message.launchAttachments(this.controller,payload.uri, payload.appIdByExtension, payload.mimeByExtension); | ||
| 839 | - } else { | ||
| 840 | - this.useInternalResourceHandler(payload.mimeByExtension, payload); | ||
| 841 | - } | ||
| 842 | - }, | ||
| 843 | - | ||
| 844 | - useInternalResourceHandler: function(mimeType, response) { | ||
| 845 | - var type = Attachments.getIconTypeFromMimeType(mimeType); | ||
| 846 | - if (!type) { | ||
| 847 | - try { | ||
| 848 | - var extensionIndex = response.uri.lastIndexOf('.'); | ||
| 849 | - if (extensionIndex > 0) { | ||
| 850 | - var extension = response.uri.substring(extensionIndex + 1).toLowerCase(); | ||
| 851 | - type = Attachments.getIconTypeFromExtension(extension); | ||
| 852 | - } | ||
| 853 | - } catch (e) { | ||
| 854 | - Mojo.Log.logException(e, "MessageAssistant.useInternalResourceHandler"); | ||
| 855 | - } | ||
| 856 | - } | ||
| 857 | - | ||
| 858 | - if (type === "type-image") { | ||
| 859 | - this.controller.stageController.pushScene('imageview', response.uri); | ||
| 860 | - } else { | ||
| 861 | - Mojo.Log.error("Email - Attachment can't be opened!"); | ||
| 862 | - this.controller.showAlertDialog({ | ||
| 863 | - onChoose: function(value) {}, | ||
| 864 | - message: $L("Cannot find an application which can open this file."), | ||
| 865 | - choices: [ | ||
| 866 | - {label:$L('OK'), value:'dismiss', type:'alert'} | ||
| 867 | - ] | ||
| 868 | - }); | ||
| 869 | - } | ||
| 870 | - }, | ||
| 871 | - | ||
| 872 | - startAttachmentDownload: function(id) { | ||
| 873 | - Mojo.Log.info("start attachment download", id); | ||
| 874 | - var progressbar = this.controller.get('progress_' + id); | ||
| 875 | - if (progressbar.visible()) { | ||
| 876 | - Mojo.Log.info("ignoring tap because attachment is already downloading"); | ||
| 877 | - } else { | ||
| 878 | - this.attachmentDLProgress.subs[id] = Message.loadAttachment(id, this.attachmentDownloadProgress.bind(this), this.attachmentError.bind(this, id)); | ||
| 879 | - | ||
| 880 | - // This makes the progressbar show up so the user gets immediate feedback. | ||
| 881 | - this.controller.get('file_size_' + id).hide(); // showing the progress bar so hide the file size | ||
| 882 | - this.controller.get('progress_' + id).show(); // ensures the progress bar is shown | ||
| 883 | - // Set the initial progress to 0% | ||
| 884 | - this.attachmentUpdateProgressbar(id, 0); | ||
| 885 | - } | ||
| 886 | - }, | ||
| 887 | - | ||
| 888 | - stopAttachmentDownload: function(id) { | ||
| 889 | - Mojo.Log.info("stop attachment download", id); | ||
| 890 | - this.attachmentDLProgress.clearSubscription(id); | ||
| 891 | - Message.cancelLoadAttachment(this.controller, id); | ||
| 892 | - | ||
| 893 | - // This makes the progressbar show up so the user gets immediate feedback. | ||
| 894 | - this.controller.get('file_size_' + id).show(); | ||
| 895 | - this.controller.get('progress_' + id).hide(); | ||
| 896 | - // Set the initial progress to 0% | ||
| 897 | - this.attachmentUpdateProgressbar(id, 0); | ||
| 898 | - }, | ||
| 899 | - | ||
| 900 | - handleInviteResponse: function(response, event) { | ||
| 901 | - Mojo.Log.info("handleInviteResponse ", response); | ||
| 902 | - var notificationAssistant = Mojo.Controller.getAppController().assistant.notificationAssistant; | ||
| 903 | - notificationAssistant.handleNotification({ type:"general", message:$L("Sending invitation response") }); | ||
| 904 | - Email.inviteResponse(this.data, response); | ||
| 905 | - this.controller.stageController.popScene(); | ||
| 906 | - }, | ||
| 907 | - | ||
| 908 | - attachmentError: function(id, err) { | ||
| 909 | - Mojo.Log.error("handleError ", err.errorText); | ||
| 910 | - this.stopAttachmentDownload(id); | ||
| 911 | - var that = this; | ||
| 912 | - var errorText; | ||
| 913 | - if (err.errorText && err.errorText.length > 0) { | ||
| 914 | - errorText = $L("Error downloading file. Server reports: #{errorText}").interpolate(err).escapeHTML(); | ||
| 915 | - } else { | ||
| 916 | - errorText = $L("Error while downloading file."); | ||
| 917 | - } | ||
| 918 | - | ||
| 919 | - this.controller.showAlertDialog({ | ||
| 920 | - onChoose: function(value) {}, | ||
| 921 | - title: $L("Unable To Download File"), | ||
| 922 | - message: errorText, | ||
| 923 | - choices: [ {label:$L('OK'), value:'dismiss', type:'alert'} ] | ||
| 924 | - }); | ||
| 925 | - }, | ||
| 926 | - | ||
| 927 | - handleAttachmentDetails: function(attachment) { | ||
| 928 | - Mojo.Log.info("handleAttachmentDetails ", attachment.id); | ||
| 929 | - | ||
| 930 | - // Update the uri for this attachment now that we got one. | ||
| 931 | - this.data.attachments.each(function(a) { | ||
| 932 | - if (a.id == attachment.id) { | ||
| 933 | - a.uri = attachment.uri; | ||
| 934 | - $break; | ||
| 935 | - } | ||
| 936 | - }); | ||
| 937 | - | ||
| 938 | - // For some reason the id needs to be a string so using toString(). | ||
| 939 | - var elem = this.controller.get((attachment.id).toString()); | ||
| 940 | - var newUri = attachment.uri; | ||
| 941 | - elem.writeAttribute('x-uri', newUri); | ||
| 942 | - elem.writeAttribute('x-mimetype', attachment.mimeType); | ||
| 943 | - | ||
| 944 | - var audioSetup = this.setupAudioTag(attachment); | ||
| 945 | - if (audioSetup) { | ||
| 946 | - // The height of the inline audio player is different so need to recalc the list height | ||
| 947 | - this.attachmentList.setStyle({height:'auto'}); // make sure the height below is the full height | ||
| 948 | - this.attachmentListHeight = parseInt(this.attachmentList.getHeight(), 10); | ||
| 949 | - } else { | ||
| 950 | - var imgElem = this.controller.get('picture_'+attachment.id); | ||
| 951 | - if (imgElem) { | ||
| 952 | - Mojo.Log.info("set img src=", newUri); | ||
| 953 | - imgElem.writeAttribute('x-uri', newUri); | ||
| 954 | - // Following uri uses extractfs to scale the image to fit 320x240. | ||
| 955 | - // This fixes problems with extremely large images causing the UI to chug. | ||
| 956 | - Attachments.processFileObject(attachment); | ||
| 957 | - var extension = attachment.extension.toLowerCase(); | ||
| 958 | - if (extension === ".jpg" || extension === ".jpeg" || extension === ".png") { | ||
| 959 | - imgElem.src = "file:///var/luna/data/extractfs/"+newUri+":0:0:320:240:3"; | ||
| 960 | - } else { | ||
| 961 | - imgElem.src = newUri; | ||
| 962 | - } | ||
| 963 | - | ||
| 964 | - var thumbnail = elem.down('.readview-image-thumbnail'); | ||
| 965 | - if (thumbnail) { | ||
| 966 | - thumbnail.src = "file:///var/luna/data/extractfs/"+newUri+":0:0:31:31:4"; | ||
| 967 | - thumbnail.show(); | ||
| 968 | - } | ||
| 969 | - } | ||
| 970 | - this.controller.get('download_icon_' + attachment.id).hide(); // remove the download arrow from the icon | ||
| 971 | - this.controller.get('progress_' + attachment.id).hide(); // ensures the progress bar is no longer shown | ||
| 972 | - this.controller.get('file_size_' + attachment.id).show(); // since progress bar is gone, show the file size | ||
| 973 | - } | ||
| 974 | - }, | ||
| 975 | - | ||
| 976 | - attachmentDownloadProgress: function(info) { | ||
| 977 | - // If the object doesn't contain a 'id' property, it isn't valid download progress | ||
| 978 | - if (info.id) { | ||
| 979 | - if (info.status == Message.ATTACHMENT_LOAD_COMPLETED_EVENT) { | ||
| 980 | - Mojo.Log.info("attachmentDownloadProgress complete for id:", info.id); | ||
| 981 | - this.attachmentDLProgress.clearSubscription(info.id); | ||
| 982 | - this.attachmentUpdateProgressbar(info.id, 100); | ||
| 983 | - | ||
| 984 | - // Final step to fully download is to get details of this attachment, including the URI. | ||
| 985 | - Message.getAttachmentDetails(this.controller, info.id, this.handleAttachmentDetails.bind(this), this.attachmentError.bind(this, info.id)); | ||
| 986 | - } | ||
| 987 | - else if (info.status == Message.ATTACHMENT_LOAD_PROGRESS_EVENT) { | ||
| 988 | - // The transports can be rather aggressive about sending progress notifications so | ||
| 989 | - // defend against that by only updating the UI periodically | ||
| 990 | - var now = new Date().getTime(); | ||
| 991 | - if (now < this.attachmentDLProgress.lastUpdate + 200) { | ||
| 992 | - this.attachmentDLProgress.progress[info.id] = info.progress; | ||
| 993 | - } else { | ||
| 994 | - this.attachmentDLProgress.lastUpdate = now; | ||
| 995 | - var that = this; | ||
| 996 | - if (info.progress !== undefined) { | ||
| 997 | - this.attachmentDLProgress.progress[info.id] = info.progress; | ||
| 998 | - } | ||
| 999 | - var progressObj = this.attachmentDLProgress.progress; | ||
| 1000 | - Object.keys(progressObj).each(function(id) { | ||
| 1001 | - var progress = progressObj[id]; | ||
| 1002 | - Mojo.Log.info("attachmentDownloadProgress id: ", id, ", progress: ", progress); | ||
| 1003 | - that.attachmentUpdateProgressbar(id, progress); | ||
| 1004 | - }); | ||
| 1005 | - } | ||
| 1006 | - } | ||
| 1007 | - } | ||
| 1008 | - }, | ||
| 1009 | - | ||
| 1010 | - attachmentUpdateProgressbar: function(id, percent) { | ||
| 1011 | - var progressGroup = this.controller.get('progress_' + id); | ||
| 1012 | - if (progressGroup) { | ||
| 1013 | - var totalWidth = 2.48; // = 248 / 100% | ||
| 1014 | - var progressWidth = Math.round(totalWidth * percent); | ||
| 1015 | - progressGroup.down(0).setStyle({width:progressWidth+"px"}); | ||
| 1016 | - var backgrndWidth = Math.round(totalWidth * (100 - percent)); | ||
| 1017 | - progressGroup.down(1).setStyle({width:backgrndWidth+"px"}); | ||
| 1018 | - } else { | ||
| 1019 | - Mojo.Log.error("Attachment ID ", id, " is invalid."); | ||
| 1020 | - } | ||
| 1021 | - }, | ||
| 1022 | - | ||
| 1023 | - hideAttachmentList: function(event) { | ||
| 1024 | - if (this.attachmentListShown) { | ||
| 1025 | - var targetRow = this.controller.get(event.target); | ||
| 1026 | - if (!targetRow.hasClassName('email-readview-attachments')) { | ||
| 1027 | - targetRow = targetRow.up('div.email-readview-attachments'); | ||
| 1028 | - } | ||
| 1029 | - | ||
| 1030 | - // Only hide the attachments list if the mousedown target was outside the | ||
| 1031 | - // list elements. Otherwise, reset the hide timer | ||
| 1032 | - if (targetRow == null) { | ||
| 1033 | - this.showHideAttachmentList(); | ||
| 1034 | - } else if (this.hideTimeout) { | ||
| 1035 | - clearTimeout(this.hideTimeout); | ||
| 1036 | - this.hideTimeout = setTimeout(this.showHideAttachmentList.bind(this), 15000); | ||
| 1037 | - } | ||
| 1038 | - } | ||
| 1039 | - }, | ||
| 1040 | - | ||
| 1041 | - showHideAttachmentList: function() { | ||
| 1042 | - if (this.hideTimeout) { | ||
| 1043 | - clearTimeout(this.hideTimeout); | ||
| 1044 | - this.hideTimeout = null; | ||
| 1045 | - } | ||
| 1046 | - | ||
| 1047 | - if (!this.attachmentListShown) { | ||
| 1048 | - this.attachmentList.show(); | ||
| 1049 | - this.attachmentsShowElem.hide(); | ||
| 1050 | - } | ||
| 1051 | - | ||
| 1052 | - var options = {reverse:this.attachmentListShown, | ||
| 1053 | - onComplete: this.animationComplete.bind(this), | ||
| 1054 | - curve: 'over-easy', | ||
| 1055 | - from: 46, | ||
| 1056 | - to: this.attachmentListHeight, | ||
| 1057 | - duration: 0.6}; | ||
| 1058 | - Mojo.Animation.animateStyle(this.attachmentList, 'height', 'bezier', options); | ||
| 1059 | - }, | ||
| 1060 | - | ||
| 1061 | - animationComplete: function(listElem, cancelled) { | ||
| 1062 | - if (!cancelled) { | ||
| 1063 | - this.attachmentListShown = !this.attachmentListShown; | ||
| 1064 | - if (this.attachmentListShown) { | ||
| 1065 | - this.attachmentsShowElem.hide(); | ||
| 1066 | - this.attachmentList.show(); | ||
| 1067 | - | ||
| 1068 | - this.hideTimeout = setTimeout(this.showHideAttachmentList.bind(this), 15000); | ||
| 1069 | - } else { | ||
| 1070 | - this.attachmentList.hide(); | ||
| 1071 | - this.attachmentsShowElem.show(); | ||
| 1072 | - } | ||
| 1073 | - } | ||
| 1074 | - }, | ||
| 1075 | - | ||
| 1076 | - /** | ||
| 1077 | - * User clicked on a hyperlink. | ||
| 1078 | - */ | ||
| 1079 | - handleLinkClicked: function(event) { | ||
| 1080 | - Mojo.Log.info("handleLinkClicked %s", event.url); | ||
| 1081 | - this.controller.serviceRequest('palm://com.palm.applicationManager', | ||
| 1082 | - { | ||
| 1083 | - method: 'open', | ||
| 1084 | - parameters: {target: event.url} | ||
| 1085 | - }); | ||
| 1086 | - }, | ||
| 1087 | - | ||
| 1088 | - /** | ||
| 1089 | - * WebView widget wants us to create a new page. | ||
| 1090 | - */ | ||
| 1091 | - handleCreatePage: function(event) { | ||
| 1092 | - Mojo.Log.info("handleCreatePage: %s", event.pageIdentifier); | ||
| 1093 | - this.controller.serviceRequest('palm://com.palm.applicationManager', | ||
| 1094 | - { | ||
| 1095 | - method: 'open', | ||
| 1096 | - parameters: { | ||
| 1097 | - 'id': 'com.palm.app.browser', | ||
| 1098 | - 'params': {scene: 'page', pageIdentifier: event.pageIdentifier} | ||
| 1099 | - } | ||
| 1100 | - }); | ||
| 1101 | - }, | ||
| 1102 | - | ||
| 1103 | - /** | ||
| 1104 | - * handle a menu command. | ||
| 1105 | - */ | ||
| 1106 | - handleCommand: function(event) { | ||
| 1107 | - if (event.type == Mojo.Event.command) { | ||
| 1108 | - try { | ||
| 1109 | - switch (event.command) { | ||
| 1110 | - case 'reply': | ||
| 1111 | - this.reply(); | ||
| 1112 | - break; | ||
| 1113 | - | ||
| 1114 | - case 'replyAll': | ||
| 1115 | - this.replyAll(); | ||
| 1116 | - break; | ||
| 1117 | - | ||
| 1118 | - case 'forward': | ||
| 1119 | - this.forward(); | ||
| 1120 | - break; | ||
| 1121 | - | ||
| 1122 | - case 'delete': | ||
| 1123 | - this.deleteEmail(); | ||
| 1124 | - break; | ||
| 1125 | - | ||
| 1126 | - case 'move': | ||
| 1127 | - this.controller.stageController.pushScene("moveto", this.account); | ||
| 1128 | - break; | ||
| 1129 | - | ||
| 1130 | - case 'mark-unread': | ||
| 1131 | - var currentLabel = this.markUnreadMenuItem.label; | ||
| 1132 | - var markRead = (currentLabel == MessageAssistant.kAppMenuMarkRead); | ||
| 1133 | - Email.setRead(this.data.id, markRead); | ||
| 1134 | - if (markRead) { | ||
| 1135 | - this.markUnreadMenuItem.label = MessageAssistant.kAppMenuMarkUnread; | ||
| 1136 | - } else { | ||
| 1137 | - this.markUnreadMenuItem.label = MessageAssistant.kAppMenuMarkRead; | ||
| 1138 | - } | ||
| 1139 | - break; | ||
| 1140 | - | ||
| 1141 | - case 'flag': | ||
| 1142 | - this.handleToggleFavorites(); | ||
| 1143 | - break; | ||
| 1144 | - | ||
| 1145 | - case Mojo.Menu.prefsCmd: | ||
| 1146 | - MenuController.showPrefs(this.controller.stageController); | ||
| 1147 | - break; | ||
| 1148 | - | ||
| 1149 | - case Mojo.Menu.helpCmd: | ||
| 1150 | - MenuController.showHelp(); | ||
| 1151 | - break; | ||
| 1152 | - } | ||
| 1153 | - } | ||
| 1154 | - catch (e) { | ||
| 1155 | - Mojo.Log.error("MessageAssistant.handleCommand: "+ e.message +" in "+ e.sourceURL +"("+ e.line +")" ); | ||
| 1156 | - } | ||
| 1157 | - } | ||
| 1158 | - // Enable prefs & help menu items | ||
| 1159 | - else if (event.type == Mojo.Event.commandEnable && | ||
| 1160 | - (event.command == Mojo.Menu.prefsCmd || event.command == Mojo.Menu.helpCmd)) { | ||
| 1161 | - event.stopPropagation(); | ||
| 1162 | - } | ||
| 1163 | - }, | ||
| 1164 | - | ||
| 1165 | - handleInlineImageSaved: function(event) { | ||
| 1166 | - if (event.status) { | ||
| 1167 | - var filepath = this.makeTitleFromUrl(event.filepath); | ||
| 1168 | - var message = $L('Saving "#{path}"').interpolate({path: filepath}); | ||
| 1169 | - Mojo.Controller.appController.showBanner( | ||
| 1170 | - {messageText: message}, | ||
| 1171 | - {banner: 'image', filename: event.filepath}); | ||
| 1172 | - } | ||
| 1173 | - }, | ||
| 1174 | - | ||
| 1175 | - makeTitleFromUrl: function(url) { | ||
| 1176 | - if (url) { | ||
| 1177 | - var result = url.match(/^.*\/([^\/]+)$/); | ||
| 1178 | - if ((result !== null) && (result.length > 1)) { | ||
| 1179 | - return result[1]; | ||
| 1180 | - } | ||
| 1181 | - } | ||
| 1182 | - | ||
| 1183 | - return url; | ||
| 1184 | - }, | ||
| 1185 | - | ||
| 1186 | - handleWebViewSingleTap: function(event) { | ||
| 1187 | - try { | ||
| 1188 | - var tapPt = Element.viewportOffset(this.webview); | ||
| 1189 | - tapPt.left = event.centerX - tapPt.left; | ||
| 1190 | - tapPt.top = event.centerY - tapPt.top; | ||
| 1191 | - | ||
| 1192 | - //Mojo.Log.info("MessageAssistant.handleWebViewSingleTap(): event.altKey=%s, tapPt.left=%d, tapPt.top=%d", event.altKey, tapPt.left, tapPt.top); | ||
| 1193 | - if (event.altKey) { | ||
| 1194 | - var popupItems = [ | ||
| 1195 | - {label: $L('Open URL'), command:'openNew'}, | ||
| 1196 | - {label: $L('Share Link'), command:'shareUrl'}, | ||
| 1197 | - {label: $L('Copy URL'), command:'copyUrl'}, | ||
| 1198 | - {label: $L('Copy to Photos'), command:'copyToPhotos'}, | ||
| 1199 | - {label: $L('Share Image'), command:'shareImage'} //, | ||
| 1200 | - //{label: $L('Set Wallpaper'), command:'setWallpaper'} | ||
| 1201 | - ]; | ||
| 1202 | - | ||
| 1203 | - var findItem = function(command) { | ||
| 1204 | - var i; | ||
| 1205 | - for (i = 0; i < popupItems.length; i++) { | ||
| 1206 | - if (popupItems[i].command === command) { | ||
| 1207 | - return popupItems[i]; | ||
| 1208 | - } | ||
| 1209 | - } | ||
| 1210 | - }; | ||
| 1211 | - | ||
| 1212 | - var selectedCommand; | ||
| 1213 | - var imageInfo; | ||
| 1214 | - | ||
| 1215 | - var saveImageCallback = function(succeeded, path) { | ||
| 1216 | - if (succeeded) { | ||
| 1217 | - switch (selectedCommand) { | ||
| 1218 | - case 'shareImage': | ||
| 1219 | - this.shareImage(imageInfo, path); | ||
| 1220 | - break; | ||
| 1221 | - case 'setWallpaper': | ||
| 1222 | - this.setWallpaper(path); | ||
| 1223 | - break; | ||
| 1224 | - case 'copyToPhotos': | ||
| 1225 | - this.showOkAlert($L('Image Saved'), | ||
| 1226 | - $L('The image was successfully added to your photo album.')); | ||
| 1227 | - break; | ||
| 1228 | - } | ||
| 1229 | - } | ||
| 1230 | - else { | ||
| 1231 | - this.showOkAlert($L('Error Saving Image'), | ||
| 1232 | - $L('There was an error saving the selected image.')); | ||
| 1233 | - } | ||
| 1234 | - }.bind(this); | ||
| 1235 | - | ||
| 1236 | - var urlInfo = {}; | ||
| 1237 | - var popupSelectFunc = function(value) { | ||
| 1238 | - selectedCommand = value; | ||
| 1239 | - | ||
| 1240 | - switch (value) { | ||
| 1241 | - case 'openNew': | ||
| 1242 | - this.newBrowserPage(urlInfo.url); | ||
| 1243 | - break; | ||
| 1244 | - case 'shareUrl': | ||
| 1245 | - this.shareUrl(urlInfo.url, urlInfo.desc); | ||
| 1246 | - break; | ||
| 1247 | - case 'copyUrl': | ||
| 1248 | - this.controller.stageController.setClipboard(urlInfo.url); | ||
| 1249 | - break; | ||
| 1250 | - case 'copyToPhotos': | ||
| 1251 | - this.webview.mojo.saveImageAtPoint(tapPt.left, tapPt.top, "/media/internal", saveImageCallback); | ||
| 1252 | - break; | ||
| 1253 | - case 'shareImage': | ||
| 1254 | - this.webview.mojo.saveImageAtPoint(tapPt.left, tapPt.top, "/tmp", saveImageCallback); | ||
| 1255 | - break; | ||
| 1256 | - case 'setWallpaper': | ||
| 1257 | - this.webview.mojo.saveImageAtPoint(tapPt.left, tapPt.top, "/media/internal", saveImageCallback); | ||
| 1258 | - break; | ||
| 1259 | - } | ||
| 1260 | - }.bind(this); | ||
| 1261 | - | ||
| 1262 | - var imageInfoResponse = function(response) { | ||
| 1263 | - imageInfo = response; | ||
| 1264 | - var usedItems = []; | ||
| 1265 | - | ||
| 1266 | - if (urlInfo.url) { | ||
| 1267 | - usedItems.push( findItem('openNew') ); | ||
| 1268 | - usedItems.push( findItem('shareUrl') ); | ||
| 1269 | - usedItems.push( findItem('copyUrl') ); | ||
| 1270 | - } | ||
| 1271 | - | ||
| 1272 | - if (response.src) { | ||
| 1273 | - usedItems.push( findItem('shareImage') ); | ||
| 1274 | - } | ||
| 1275 | - | ||
| 1276 | - if (this.supportedImageType(response.src, response.mimeType)) { | ||
| 1277 | - usedItems.push( findItem('copyToPhotos') ); | ||
| 1278 | - //usedItems.push( findItem('setWallpaper') ); | ||
| 1279 | - } | ||
| 1280 | - | ||
| 1281 | - if (usedItems.length) { | ||
| 1282 | - this.controller.popupSubmenu({ onChoose: popupSelectFunc, items: usedItems }); | ||
| 1283 | - } | ||
| 1284 | - }.bind(this); | ||
| 1285 | - | ||
| 1286 | - var urlInspectResponse = function(response) { | ||
| 1287 | - urlInfo = response || {}; | ||
| 1288 | - this.webview.mojo.getImageInfoAtPoint(tapPt.left, tapPt.top, imageInfoResponse); | ||
| 1289 | - }.bind(this); | ||
| 1290 | - | ||
| 1291 | - this.webview.mojo.inspectUrlAtPoint(tapPt.left, tapPt.top, urlInspectResponse); | ||
| 1292 | - } | ||
| 1293 | - } | ||
| 1294 | - catch (e) { | ||
| 1295 | - Mojo.Log.logException(e); | ||
| 1296 | - } | ||
| 1297 | - }, | ||
| 1298 | - | ||
| 1299 | - supportedImageType:function(url, mimeType) { | ||
| 1300 | - switch (this.getImageType(url, mimeType)) { | ||
| 1301 | - case 'jpeg': | ||
| 1302 | - case 'png': | ||
| 1303 | - case 'bmp': // We only support 24/32 bit BMP's and don't differentiate here | ||
| 1304 | - // GIF not yet supported | ||
| 1305 | - return true; | ||
| 1306 | - default: | ||
| 1307 | - return false; | ||
| 1308 | - } | ||
| 1309 | - }, | ||
| 1310 | - | ||
| 1311 | - getImageType: function(url, mimeType) { | ||
| 1312 | - url = url || ''; | ||
| 1313 | - mimeType = mimeType || ''; | ||
| 1314 | - var suffix = ''; | ||
| 1315 | - try { | ||
| 1316 | - suffix = this.getResourceExtension(url); | ||
| 1317 | - if (suffix === null) { | ||
| 1318 | - suffix = ''; | ||
| 1319 | - } | ||
| 1320 | - } | ||
| 1321 | - catch (e) { | ||
| 1322 | - Mojo.Log.logException(e); | ||
| 1323 | - } | ||
| 1324 | - | ||
| 1325 | - suffix = suffix.toLowerCase(); | ||
| 1326 | - mimeType = mimeType.toLowerCase(); | ||
| 1327 | - | ||
| 1328 | - if (suffix === 'jpg' || suffix === 'jpeg' || suffix === 'jpe' || mimeType === 'image/jpeg') { | ||
| 1329 | - return 'jpeg'; | ||
| 1330 | - } | ||
| 1331 | - else if (suffix === 'bmp' || mimeType === 'image/bmp') { | ||
| 1332 | - return 'bmp'; | ||
| 1333 | - } | ||
| 1334 | - else if (suffix === 'png' || mimeType === 'image/png') { | ||
| 1335 | - return 'png'; | ||
| 1336 | - } | ||
| 1337 | - else if (suffix === 'gif' || mimeType === 'image/gif') { | ||
| 1338 | - return 'gif'; | ||
| 1339 | - } | ||
| 1340 | - else { | ||
| 1341 | - return 'unknown'; | ||
| 1342 | - } | ||
| 1343 | - }, | ||
| 1344 | - | ||
| 1345 | - getResourceExtension: function(url) { | ||
| 1346 | - var p = new Poly9.URLParser(url); | ||
| 1347 | - | ||
| 1348 | - var matches = p.getPathname().match(/\.([^\.]*)$/i); | ||
| 1349 | - if (matches) { | ||
| 1350 | - return matches[1]; | ||
| 1351 | - } | ||
| 1352 | - else { | ||
| 1353 | - return null; | ||
| 1354 | - } | ||
| 1355 | - }, | ||
| 1356 | - | ||
| 1357 | - newBrowserPage: function(url) { | ||
| 1358 | - this.controller.serviceRequest('palm://com.palm.applicationManager', | ||
| 1359 | - { | ||
| 1360 | - method: 'open', | ||
| 1361 | - parameters: {target: url} | ||
| 1362 | - }); | ||
| 1363 | - }, | ||
| 1364 | - | ||
| 1365 | - shareUrl: function(url, title) { | ||
| 1366 | - if (url === undefined) { | ||
| 1367 | - return; | ||
| 1368 | - } | ||
| 1369 | - | ||
| 1370 | - if (!title) { | ||
| 1371 | - try { | ||
| 1372 | - title = $L("page at #{host}").interpolate({host: UrlUtil.getUrlHost(url)}); | ||
| 1373 | - } | ||
| 1374 | - catch (e) { | ||
| 1375 | - title = url; | ||
| 1376 | - } | ||
| 1377 | - } | ||
| 1378 | - | ||
| 1379 | - var text = $L("Here's a website I think you'll like: <a href='#{src}'>#{title}</a>").interpolate( | ||
| 1380 | - {src: url, title: title}); | ||
| 1381 | - var parameters = { | ||
| 1382 | - summary: $L('Check out this web page...'), | ||
| 1383 | - text: text | ||
| 1384 | - }; | ||
| 1385 | - var email = new Email(); | ||
| 1386 | - email.evalParams(parameters); | ||
| 1387 | - AppAssistant.openComposeStage(email); | ||
| 1388 | - }, | ||
| 1389 | - | ||
| 1390 | - shareImage: function(imageInfoObj, pathToImage) { | ||
| 1391 | - var title; | ||
| 1392 | - if (imageInfoObj.title && imageInfoObj.title.length) { | ||
| 1393 | - title = imageInfoObj.title; | ||
| 1394 | - } | ||
| 1395 | - else if (imageInfoObj.altText && imageInfoObj.altText.length) { | ||
| 1396 | - title = imageInfoObj.altText; | ||
| 1397 | - } | ||
| 1398 | - else { | ||
| 1399 | - var p = new Poly9.URLParser(imageInfoObj.src); | ||
| 1400 | - title = $L('picture link'); | ||
| 1401 | - try { | ||
| 1402 | - if (imageInfoObj.src !== 'data:') { | ||
| 1403 | - title = $L("picture at #{host}").interpolate( | ||
| 1404 | - {host: p.getHost()}); | ||
| 1405 | - } | ||
| 1406 | - } | ||
| 1407 | - catch (e) {} | ||
| 1408 | - } | ||
| 1409 | - | ||
| 1410 | - var text = $L("Here's a picture I think you'll like: <a href='#{src}'>#{title}</a>").interpolate( | ||
| 1411 | - {src: imageInfoObj.src, title: title}); | ||
| 1412 | - | ||
| 1413 | - var parameters = { | ||
| 1414 | - summary: $L('Check out this picture...'), | ||
| 1415 | - text: text, | ||
| 1416 | - attachments: [{fullPath: pathToImage}] | ||
| 1417 | - }; | ||
| 1418 | - var email = new Email(); | ||
| 1419 | - email.evalParams(parameters); | ||
| 1420 | - AppAssistant.openComposeStage(email); | ||
| 1421 | - }, | ||
| 1422 | - | ||
| 1423 | - setWallpaper: function(pathToImage) { | ||
| 1424 | - var errorTitle = $L("Error Setting Wallpaper"); | ||
| 1425 | - | ||
| 1426 | - var onSetSuccess = function(response) { | ||
| 1427 | - this.showOkAlert($L("Wallpaper has been set"), | ||
| 1428 | - $L("The image has been successfully set as your wallpaper.")); | ||
| 1429 | - }.bind(this); | ||
| 1430 | - | ||
| 1431 | - var onSetFailure = function(response) { | ||
| 1432 | - this.showOkAlert(errorTitle, $L("Cannot set picture as current wallpaper.")); | ||
| 1433 | - }.bind(this); | ||
| 1434 | - | ||
| 1435 | - var onImportSuccess = function(response) { | ||
| 1436 | - this.controller.serviceRequest('palm://com.palm.systemservice/', | ||
| 1437 | - { | ||
| 1438 | - method : 'setPreferences', | ||
| 1439 | - parameters: {wallpaper: response.wallpaper}, | ||
| 1440 | - onSuccess: onSetSuccess, | ||
| 1441 | - onFailure: onSetFailure | ||
| 1442 | - }); | ||
| 1443 | - }.bind(this); | ||
| 1444 | - | ||
| 1445 | - var onImportFailure = function() { | ||
| 1446 | - this.showOkAlert(errorTitle, $L("Cannot import picture into wallpaper database.")); | ||
| 1447 | - }.bind(this); | ||
| 1448 | - | ||
| 1449 | - this.controller.serviceRequest('palm://com.palm.systemservice/', { | ||
| 1450 | - method : 'wallpaper/importWallpaper', | ||
| 1451 | - parameters: { | ||
| 1452 | - target: encodeURIComponent(pathToImage), | ||
| 1453 | - scale: "1.0" | ||
| 1454 | - }, | ||
| 1455 | - onSuccess: onImportSuccess, | ||
| 1456 | - onFailure: onImportFailure | ||
| 1457 | - }); | ||
| 1458 | - }, | ||
| 1459 | - | ||
| 1460 | - showOkAlert: function(title, message) | ||
| 1461 | - { | ||
| 1462 | - this.controller.showAlertDialog({ | ||
| 1463 | - title: title, message: message, | ||
| 1464 | - choices:[{label:$L('OK'), value:'1', type:'dismiss'}] | ||
| 1465 | - }); | ||
| 1466 | - }, | ||
| 1467 | - | ||
| 1468 | - handleNextMessagesResponse: function(response) { | ||
| 1469 | - this.nextMessages = response; | ||
| 1470 | - | ||
| 1471 | - var prevEmail = this.controller.get('previous_email'); | ||
| 1472 | - if (!prevEmail) { | ||
| 1473 | - Mojo.Log.error("previous_email element does not yet exist"); | ||
| 1474 | - } else { | ||
| 1475 | - if (response.newer === undefined || response.newer.end) { | ||
| 1476 | - // hide 'previous_email' because there's no more emails in that direction | ||
| 1477 | - prevEmail.addClassName('disabled'); | ||
| 1478 | - } else { | ||
| 1479 | - prevEmail.removeClassName('disabled'); | ||
| 1480 | - } | ||
| 1481 | - } | ||
| 1482 | - | ||
| 1483 | - var nextEmail = this.controller.get('next_email'); | ||
| 1484 | - if (!nextEmail) { | ||
| 1485 | - Mojo.Log.error("next_email element does not yet exist"); | ||
| 1486 | - } else { | ||
| 1487 | - if (response.older === undefined || response.older.end) { | ||
| 1488 | - // hide 'next_email' because there's no more emails in that direction | ||
| 1489 | - nextEmail.addClassName('disabled'); | ||
| 1490 | - } else { | ||
| 1491 | - nextEmail.removeClassName('disabled'); | ||
| 1492 | - } | ||
| 1493 | - } | ||
| 1494 | - }, | ||
| 1495 | - | ||
| 1496 | - gotoNextEmail: function(direction) { | ||
| 1497 | - if (this.nextMessages !== undefined && this.nextMessages[direction] !== undefined) { | ||
| 1498 | - var details = this.nextMessages[direction]; | ||
| 1499 | - if (!details.end && details.id > 0) { | ||
| 1500 | - if (this.transition !== null) { | ||
| 1501 | - this.transition.cleanup(); | ||
| 1502 | - } | ||
| 1503 | - this.transition = this.controller.prepareTransition(Mojo.Transition.crossFade, false); | ||
| 1504 | - this.prepareForNewMessage(details); | ||
| 1505 | - } | ||
| 1506 | - } | ||
| 1507 | - }, | ||
| 1508 | - | ||
| 1509 | - prepareForNewMessage: function(details) { | ||
| 1510 | - this.data = { id: details.id, senderDetails:{} }; // data.id | ||
| 1511 | - this.account = {}; | ||
| 1512 | - this.gotFirstResponse = false; | ||
| 1513 | - this.bodyLeftOffset = 0; | ||
| 1514 | - // Clear out the old email body by loading a simple empty page | ||
| 1515 | - this.webview.mojo.openURL(Mojo.appPath + "emptypage.html"); | ||
| 1516 | - this.plainTextBody.hide(); | ||
| 1517 | - | ||
| 1518 | - // stop listening to all these | ||
| 1519 | - this.controller.get('previous_email').stopObserving(Mojo.Event.tap, this.boundGotoNextEmailNewer); | ||
| 1520 | - this.controller.get('next_email').stopObserving(Mojo.Event.tap, this.boundGotoNextEmailOlder); | ||
| 1521 | - if (this.recipientController) { | ||
| 1522 | - this.recipientController.up(".palm-row").stopObserving(Mojo.Event.tap, this.boundShowHideRecipients, true); | ||
| 1523 | - } | ||
| 1524 | - var elem; | ||
| 1525 | - elem = this.controller.get('invite-accept'); | ||
| 1526 | - if (elem) { | ||
| 1527 | - elem.stopObserving(Mojo.Event.tap, this.boundHandleInviteResponseAccept); | ||
| 1528 | - } | ||
| 1529 | - elem = this.controller.get('invite-tentative'); | ||
| 1530 | - if (elem) { | ||
| 1531 | - elem.stopObserving(Mojo.Event.tap, this.boundHandleInviteResponseTentative); | ||
| 1532 | - } | ||
| 1533 | - this.controller.get('invite-decline'); | ||
| 1534 | - if (elem) { | ||
| 1535 | - elem.stopObserving(Mojo.Event.tap, this.boundHandleInviteResponseDecline); | ||
| 1536 | - } | ||
| 1537 | - | ||
| 1538 | - // reset the horizontal positioning of these two blocks. | ||
| 1539 | - this.emailHeaderBlock.setStyle({ 'left': '0px' }); | ||
| 1540 | - this.emailPicturesBlock.setStyle({ 'left': '0px' }); | ||
| 1541 | - | ||
| 1542 | - // Subscribe to the new message | ||
| 1543 | - if (this.waitingForMessageBodyTimeout !== undefined) { | ||
| 1544 | - clearTimeout(this.waitingForMessageBodyTimeout); | ||
| 1545 | - this.waitingForMessageBodyTimeout = undefined; | ||
| 1546 | - } | ||
| 1547 | - if (this.messageSubscription) { | ||
| 1548 | - this.messageSubscription.cancel(); | ||
| 1549 | - } | ||
| 1550 | - this.messageSubscription = new Mojo.Service.Request(Message.identifier, { | ||
| 1551 | - method: 'messageDetail', | ||
| 1552 | - parameters: { 'message':this.data.id, subscribe:true }, | ||
| 1553 | - onSuccess: this.messageDetailsUpdated.bind(this), | ||
| 1554 | - onFailure: this.waitMessageError.bind(this) | ||
| 1555 | - }); | ||
| 1556 | - | ||
| 1557 | - Message.getFolderAndAccount(this.controller, this.data.id, this.folderAndAccountDetails.bind(this)); | ||
| 1558 | - }, | ||
| 1559 | - | ||
| 1560 | - /** | ||
| 1561 | - * Called by the webview widget when setup is complete? | ||
| 1562 | - */ | ||
| 1563 | - ready: function() { | ||
| 1564 | - this.webview.mojo.addUrlRedirect("^file:.*", false, "", 0); | ||
| 1565 | - this.webview.mojo.addUrlRedirect(".*", true, "", 0); | ||
| 1566 | - }, | ||
| 1567 | - | ||
| 1568 | - setupMessage: function() { | ||
| 1569 | - // Setup the WebView for the body text | ||
| 1570 | - // TODO autowidth to true? | ||
| 1571 | - var emailStageController = Mojo.Controller.appController.getStageController("email"); | ||
| 1572 | - var attr = {minFontSize:18, | ||
| 1573 | - cacheAdapter:true, | ||
| 1574 | - fitWidth: false, | ||
| 1575 | - virtualpagewidth: emailStageController.window.innerWidth, | ||
| 1576 | - minimumpageheight: 32, // Start out very short in case the message body empty | ||
| 1577 | - showClickedLink:true}; | ||
| 1578 | - this.controller.setupWidget('email_body_text', attr); | ||
| 1579 | - this.controller.setupWidget('email_no_body_spinner', { spinnerSize: Mojo.Widget.spinnerSmall }); | ||
| 1580 | - | ||
| 1581 | - this.webview = this.controller.get('email_body_text'); | ||
| 1582 | - this.webview.addEventListener(Mojo.Event.webViewUrlRedirect, this.boundHandleLinkClicked, false); | ||
| 1583 | - this.webview.addEventListener(Mojo.Event.webViewMimeNotSupported, this.boundHandleLinkClicked, false); | ||
| 1584 | - this.webview.addEventListener(Mojo.Event.webViewMimeHandoff, this.boundHandleLinkClicked, false); | ||
| 1585 | - this.webview.addEventListener(Mojo.Event.webViewImageSaved, this.boundHandleInlineImageSaved, false); | ||
| 1586 | - this.webview.addEventListener('singletap', this.boundHandleWebViewSingleTap, true); | ||
| 1587 | - | ||
| 1588 | - this.waitingForMessageBody = undefined; | ||
| 1589 | - // subscribe to the message details because the transport may need to send updates in the case where the | ||
| 1590 | - // email body and/or attachments isn't yet downloaded | ||
| 1591 | - this.messageSubscription = new Mojo.Service.Request(Message.identifier, { | ||
| 1592 | - method: 'messageDetail', | ||
| 1593 | - parameters: { 'message':this.data.id, subscribe:true }, | ||
| 1594 | - onSuccess: this.messageDetailsUpdated.bind(this), | ||
| 1595 | - onFailure: this.waitMessageError.bind(this) | ||
| 1596 | - }); | ||
| 1597 | - }, | ||
| 1598 | - | ||
| 1599 | - orientationChanged: function(orientation) { | ||
| 1600 | - if (orientation === "left" || orientation === "right") { | ||
| 1601 | - this.controller.sceneElement.addClassName('landscape'); | ||
| 1602 | - } else { | ||
| 1603 | - this.controller.sceneElement.removeClassName('landscape'); | ||
| 1604 | - } | ||
| 1605 | - }, | ||
| 1606 | - | ||
| 1607 | - focusEmailStage: function() { | ||
| 1608 | - if (this.focusStageTimer) { | ||
| 1609 | - this.focusStageTimer = undefined; | ||
| 1610 | - AppAssistant.focusEmailStage(); | ||
| 1611 | - } | ||
| 1612 | - }, | ||
| 1613 | - | ||
| 1614 | - // This is called from accountpreference assistant when the user removes the account | ||
| 1615 | - accountDeletedNotification: function(accountId) { | ||
| 1616 | - if (accountId === this.account.account) { | ||
| 1617 | - Mojo.Log.warn("MessageAssistant is showing a deleted account, setting up for cleanup"); | ||
| 1618 | - this.popOnActivate = true; | ||
| 1619 | - } | ||
| 1620 | - }, | ||
| 1621 | - | ||
| 1622 | - setup: function() { | ||
| 1623 | - this.delayActivate = true; | ||
| 1624 | - this.messageTarget = this.controller.get('readview-main'); | ||
| 1625 | - this.messageTarget.observe('mousedown', this.hideAttachmentList.bind(this), true); | ||
| 1626 | - this.setupMessage(); | ||
| 1627 | - | ||
| 1628 | - this.emailHeaderBlock = this.controller.get('email_header_block'); | ||
| 1629 | - this.plainTextBody = this.controller.get('email_text'); | ||
| 1630 | - this.emailPicturesBlock = this.controller.get('email_pictures_list'); | ||
| 1631 | - | ||
| 1632 | - this.controller.get('email-readview-attachments-list').observe(Mojo.Event.tap, this.handleAttachmentTapped.bind(this)); | ||
| 1633 | - this.attachmentsShowElem = this.controller.get('show-hide-multi-attachments'); | ||
| 1634 | - this.attachmentsShowElem.observe(Mojo.Event.tap, this.showHideAttachmentList.bind(this)); | ||
| 1635 | - | ||
| 1636 | - this.cmdMenuModel = { | ||
| 1637 | - visible:true, | ||
| 1638 | - items: [ | ||
| 1639 | - {label:$L('Reply'), icon:'reply', command:'reply'}, | ||
| 1640 | - {label:$L('Reply all'), icon:'reply-all', command:'replyAll'}, | ||
| 1641 | - {label:$L('Forward'), icon:'forward-email', command:'forward'}, | ||
| 1642 | - {label:$L('Delete'), icon:'delete', command:'delete'} | ||
| 1643 | - ]}; | ||
| 1644 | - this.controller.setupWidget(Mojo.Menu.commandMenu, undefined, this.cmdMenuModel); | ||
| 1645 | - | ||
| 1646 | - this.markUnreadMenuItem = {label:MessageAssistant.kAppMenuMarkUnread, command:'mark-unread'}; | ||
| 1647 | - this.markSetFlagMenuItem = {label:MessageAssistant.kAppMenuSetFlag, command:'flag'}; | ||
| 1648 | - this.appMenuModel = { | ||
| 1649 | - visible:true, | ||
| 1650 | - items: [ | ||
| 1651 | - this.markUnreadMenuItem, | ||
| 1652 | - this.markSetFlagMenuItem, | ||
| 1653 | - {label:$L('Move to folder...'), command:'move'} | ||
| 1654 | - ]}; | ||
| 1655 | - this.controller.setupWidget(Mojo.Menu.appMenu, undefined, this.appMenuModel); | ||
| 1656 | - | ||
| 1657 | - Message.getFolderAndAccount(this.controller, this.data.id, this.folderAndAccountDetails.bind(this)); | ||
| 1658 | - | ||
| 1659 | - this.recipsDrawer = { openProperty: false }; | ||
| 1660 | - this.controller.setupWidget('email_recipients_drawer', {unstyled:true, modelProperty:'openProperty'}, this.recipsDrawer); | ||
| 1661 | - this.recipsDrawer.element = this.controller.get('email_recipients_drawer'); | ||
| 1662 | - | ||
| 1663 | - this.emailPicturesBlock.observe(Mojo.Event.tap, this.handleImageTapped.bind(this)); | ||
| 1664 | - // stop gesture events on pictures so they don't go to the webview widget | ||
| 1665 | - this.emailPicturesBlock.observe('gesturestart', function(event) { event.stop(); }, false); | ||
| 1666 | - this.emailPicturesBlock.observe('gesturechange', function(event) { event.stop(); }, false); | ||
| 1667 | - this.emailPicturesBlock.observe('gestureend', function(event) { event.stop(); }, false); | ||
| 1668 | - | ||
| 1669 | - this.controller.get('email_from').observe(Mojo.Event.tap, this.handleSenderTap.bind(this)); | ||
| 1670 | - this.controller.get('email_recipients').observe(Mojo.Event.tap, this.handleRecipientListSelect.bind(this)); | ||
| 1671 | - | ||
| 1672 | - this.boundUpdateRecipientStatus = this.updateRecipientStatus.bind(this); | ||
| 1673 | - Mojo.Event.listen(this.controller.stageController.document, Mojo.Event.activate, this.boundUpdateRecipientStatus); | ||
| 1674 | - | ||
| 1675 | - Mojo.Event.listen(this.controller.getSceneScroller(), Mojo.Event.scrollStarting, this.addAsScrollListener.bind(this)); | ||
| 1676 | - }, | ||
| 1677 | - | ||
| 1678 | - cleanup: function() { | ||
| 1679 | - if (this.waitingForMessageBodyTimeout !== undefined) { | ||
| 1680 | - clearTimeout(this.waitingForMessageBodyTimeout); | ||
| 1681 | - this.waitingForMessageBodyTimeout = undefined; | ||
| 1682 | - } | ||
| 1683 | - | ||
| 1684 | - if (this.focusStageTimer !== undefined) { | ||
| 1685 | - clearTimeout(this.focusStageTimer); | ||
| 1686 | - } | ||
| 1687 | - | ||
| 1688 | - this.webview.removeEventListener(Mojo.Event.webViewUrlRedirect, this.boundHandleLinkClicked, false); | ||
| 1689 | - this.webview.removeEventListener(Mojo.Event.webViewMimeNotSupported, this.boundHandleLinkClicked, false); | ||
| 1690 | - this.webview.removeEventListener(Mojo.Event.webViewMimeHandoff, this.boundHandleLinkClicked, false); | ||
| 1691 | - this.webview.removeEventListener(Mojo.Event.webViewImageSaved, this.boundHandleInlineImageSaved, false); | ||
| 1692 | - this.webview.removeEventListener('singletap', this.boundHandleWebViewSingleTap, true); | ||
| 1693 | - | ||
| 1694 | - if (this.messageSubscription) { | ||
| 1695 | - this.messageSubscription.cancel(); | ||
| 1696 | - } | ||
| 1697 | - Mojo.Event.stopListening(this.controller.stageController.document, Mojo.Event.activate, this.boundUpdateRecipientStatus); | ||
| 1698 | - Message.closeMessage(this.controller, this.data.id); | ||
| 1699 | - }, | ||
| 1700 | - | ||
| 1701 | - aboutToActivate: function(callback) { | ||
| 1702 | - if (this.delayActivate === true) { | ||
| 1703 | - this.readyToActivateCallback = callback; | ||
| 1704 | - } else { | ||
| 1705 | - callback(); | ||
| 1706 | - } | ||
| 1707 | - }, | ||
| 1708 | - | ||
| 1709 | - activate: function() { | ||
| 1710 | - // If the scene is invalid (usually because the underlying account was deleted), | ||
| 1711 | - // just pop the scene and no more. | ||
| 1712 | - if (this.popOnActivate === true) { | ||
| 1713 | - this.controller.stageController.popScene(); | ||
| 1714 | - return; | ||
| 1715 | - } | ||
| 1716 | - | ||
| 1717 | - // save the current scene controller physics parameters | ||
| 1718 | - var scroller = this.controller.getSceneScroller(); | ||
| 1719 | - this.savedFlickSpeed = scroller.mojo.kFlickSpeed; | ||
| 1720 | - this.savedFlickRatio = scroller.mojo.kFlickRatio; | ||
| 1721 | - scroller.mojo.updatePhysicsParameters({flickSpeed: 0.12, flickRatio: 0.2}); | ||
| 1722 | - | ||
| 1723 | - // If the scene is ready to activate and it needs to be focused, do that now. | ||
| 1724 | - if (this.focusStageTimer !== undefined) { | ||
| 1725 | - clearTimeout(this.focusStageTimer); | ||
| 1726 | - this.focusEmailStage(); | ||
| 1727 | - } | ||
| 1728 | - | ||
| 1729 | - // prerenderData is only set if the data was supplied from the list assistant. If the | ||
| 1730 | - // service already send a response, it will not include the prerenderData property. | ||
| 1731 | - if (this.data.prerenderData === true) { | ||
| 1732 | - this.prerenderMessage(this.data); | ||
| 1733 | - } | ||
| 1734 | - }, | ||
| 1735 | - | ||
| 1736 | - deactivate: function() { | ||
| 1737 | - // restore the current scene controller physics parameters | ||
| 1738 | - var scroller = this.controller.getSceneScroller(); | ||
| 1739 | - scroller.mojo.updatePhysicsParameters({flickSpeed: this.savedFlickSpeed, flickRatio: this.savedFlickRatio}); | ||
| 1740 | - }, | ||
| 1741 | - | ||
| 1742 | - reply: function() { | ||
| 1743 | - var email = new Email(); | ||
| 1744 | - email.createReply(this.data, this.account.login); | ||
| 1745 | - MenuController.showComposeView(email); | ||
| 1746 | - }, | ||
| 1747 | - | ||
| 1748 | - replyAll: function() { | ||
| 1749 | - var email = new Email(); | ||
| 1750 | - email.createReplyAll(this.data, this.account.login); | ||
| 1751 | - MenuController.showComposeView(email); | ||
| 1752 | - }, | ||
| 1753 | - | ||
| 1754 | - forward: function() { | ||
| 1755 | - var email = new Email(); | ||
| 1756 | - email.createForward(this.data, this.account.login); | ||
| 1757 | - MenuController.showComposeView(email); | ||
| 1758 | - }, | ||
| 1759 | - | ||
| 1760 | - deleteEmail: function() { | ||
| 1761 | - Email.setDeleted(this.data.id, true); | ||
| 1762 | - this.controller.stageController.popScene(); | ||
| 1763 | - } | ||
| 1764 | -}); | ||
| 1765 | - | ||
| 1766 | -MessageAssistant.kAppMenuMarkRead = $L('Mark as read'); | ||
| 1767 | -MessageAssistant.kAppMenuMarkUnread = $L('Mark as unread'); | ||
| 1768 | -MessageAssistant.kAppMenuSetFlag = $L('Set flag'); | ||
| 1769 | -MessageAssistant.kAppMenuClearFlag = $L('Clear flag'); | ||
| 1770 | - | ||
| 1771 | - | ||
| 1772 | +/* Copyright 2009 Palm, Inc. All rights reserved. */ | ||
| 1773 | + | ||
| 1774 | +var MessageAssistant = Class.create({ | ||
| 1775 | + initialize : function(targetEmail, folderId, focusStage, detailsObj) { | ||
| 1776 | + this.data = { id: targetEmail, senderDetails:{} }; // data.id | ||
| 1777 | + // This data is used to pre-render info in case the mailservice isn't able to respond quickly enough | ||
| 1778 | + if (detailsObj) { | ||
| 1779 | + this.data.prerenderData = true; | ||
| 1780 | + this.data.displayName = detailsObj.displayName; | ||
| 1781 | + this.data.summary = detailsObj.summary; | ||
| 1782 | + this.data.timeStamp = detailsObj.timeStamp; | ||
| 1783 | + this.data.flags = detailsObj.flags; | ||
| 1784 | + this.data.priority = detailsObj.priority; | ||
| 1785 | + } | ||
| 1786 | + this.folderId = folderId; | ||
| 1787 | + this.account = {}; | ||
| 1788 | + this.gotFirstResponse = false; | ||
| 1789 | + this.bodyLeftOffset = 0; | ||
| 1790 | + this.transition = null; | ||
| 1791 | + this.waitingForMessageBodyTimeout = undefined; | ||
| 1792 | + this.attachmentDLProgress = { | ||
| 1793 | + lastUpdate:0, | ||
| 1794 | + progress:{}, | ||
| 1795 | + subs:{}, | ||
| 1796 | + clearSubscription: function(id) { | ||
| 1797 | + try { | ||
| 1798 | + this.subs[id].cancel(); | ||
| 1799 | + delete (this.subs[id]); | ||
| 1800 | + delete (this.progress[id]); | ||
| 1801 | + } catch (e) { | ||
| 1802 | + Mojo.Log.logException(e, "clearSubscription"); | ||
| 1803 | + } | ||
| 1804 | + } | ||
| 1805 | + }; | ||
| 1806 | + | ||
| 1807 | + this.boundShowHideRecipients = this.showHideRecipients.bind(this); | ||
| 1808 | + this.boundGotoNextEmailNewer = this.gotoNextEmail.bind(this, 'newer'); | ||
| 1809 | + this.boundGotoNextEmailOlder = this.gotoNextEmail.bind(this, 'older'); | ||
| 1810 | + this.boundHandleInviteResponseAccept = this.handleInviteResponse.bind(this, 'accept'); | ||
| 1811 | + this.boundHandleInviteResponseTentative = this.handleInviteResponse.bind(this, 'tentative'); | ||
| 1812 | + this.boundHandleInviteResponseDecline = this.handleInviteResponse.bind(this, 'decline'); | ||
| 1813 | + this.boundHandleInviteResponseRemove = this.handleInviteResponse.bind(this, 'remove'); | ||
| 1814 | + this.boundHandleLinkClicked = this.handleLinkClicked.bind(this); | ||
| 1815 | + this.boundHandleInlineImageSaved = this.handleInlineImageSaved.bind(this); | ||
| 1816 | + this.boundHandleWebViewSingleTap = this.handleWebViewSingleTap.bind(this); | ||
| 1817 | + | ||
| 1818 | + if (focusStage === true) { | ||
| 1819 | + this.focusStageTimer = this.focusEmailStage.bind(this).delay(0.6); | ||
| 1820 | + } | ||
| 1821 | + }, | ||
| 1822 | + | ||
| 1823 | + addAsScrollListener: function(event) { | ||
| 1824 | + event.scroller.addListener(this); | ||
| 1825 | + }, | ||
| 1826 | + | ||
| 1827 | + moved: function() { | ||
| 1828 | + var scrollOffset = this.messageTarget.viewportOffset(); | ||
| 1829 | + if (this.bodyLeftOffset === scrollOffset.left) { | ||
| 1830 | + return; | ||
| 1831 | + } else if (this.webview !== undefined) { | ||
| 1832 | + this.bodyLeftOffset = scrollOffset.left; | ||
| 1833 | + // Get the width of the browseradapter since that should tell the truth about its width | ||
| 1834 | + var webviewWidth = this.webview.down().getWidth(); | ||
| 1835 | + //console.log("offsets: ov x=" + scrollOffset.left + ", w=" + this.emailHeaderBlock.getWidth() + ", wh=" + webviewWidth); | ||
| 1836 | + | ||
| 1837 | + if (scrollOffset.left > 0) { | ||
| 1838 | + scrollOffset.left = 0; | ||
| 1839 | + } else { | ||
| 1840 | + var rightExtent = (this.emailHeaderBlock.getWidth() - webviewWidth); | ||
| 1841 | + if (scrollOffset.left < rightExtent) { | ||
| 1842 | + scrollOffset.left = rightExtent; | ||
| 1843 | + } | ||
| 1844 | + } | ||
| 1845 | + | ||
| 1846 | + // move the header block & the attached pictures block so they appear to not scroll horizontally | ||
| 1847 | + var leftOffset = -scrollOffset.left + 'px'; | ||
| 1848 | + this.emailHeaderBlock.setStyle({ 'left': leftOffset }); | ||
| 1849 | + this.emailPicturesBlock.setStyle({ 'left': leftOffset }); | ||
| 1850 | + } | ||
| 1851 | + }, | ||
| 1852 | + | ||
| 1853 | + displayContactAvatarAndPresence: function(baseId, storageId, resp) { | ||
| 1854 | + var nameId = baseId + "-name"; | ||
| 1855 | + var avatarId = baseId + "-photo"; | ||
| 1856 | + var presenceId = baseId + "-presence"; | ||
| 1857 | + | ||
| 1858 | + // If this person isn't in contact, give him ID=0. This is done in case the | ||
| 1859 | + // contact was deleted, in which case the old settings need to be cleared. | ||
| 1860 | + if (!resp.record) { | ||
| 1861 | + resp.record = { id:0 }; | ||
| 1862 | + } | ||
| 1863 | + | ||
| 1864 | + if (baseId === "email-sender") { | ||
| 1865 | + this.data.fromID = resp.record.id; | ||
| 1866 | + | ||
| 1867 | +//<Reminder Info> | ||
| 1868 | + if (resp.record && resp.record.reminder) { | ||
| 1869 | + if (this.contactReminder === undefined) { | ||
| 1870 | + this.contactReminder = new ContactReminder(); | ||
| 1871 | + } | ||
| 1872 | + this.contactReminder.displayReminder(resp); | ||
| 1873 | + } | ||
| 1874 | + } else { | ||
| 1875 | + this.controller.get(storageId).writeAttribute('contactid', resp.record.id); | ||
| 1876 | + } | ||
| 1877 | + | ||
| 1878 | + var nameElem = this.controller.get(nameId); | ||
| 1879 | + if (resp.record.displayText) { | ||
| 1880 | + nameElem.update(resp.record.displayText); | ||
| 1881 | + } else if (resp.record.firstName && resp.record.lastName) { | ||
| 1882 | + nameElem.update(resp.record.firstName + " " + resp.record.lastName); | ||
| 1883 | + } else if (resp.record.firstName) { | ||
| 1884 | + nameElem.update(resp.record.firstName); | ||
| 1885 | + } else if (resp.record.lastName) { | ||
| 1886 | + nameElem.update(resp.record.lastName); | ||
| 1887 | + } | ||
| 1888 | + | ||
| 1889 | + if (resp.record.pictureLocSquare) { | ||
| 1890 | + Mojo.Log.info("Displaying sender's picture ", resp.record.pictureLocSquare); | ||
| 1891 | + var imgElem = this.controller.get(avatarId); | ||
| 1892 | + imgElem.src = "file://" + resp.record.pictureLocSquare; | ||
| 1893 | + var imgFrame = imgElem.up('.from-photo'); | ||
| 1894 | + if (imgFrame !== undefined) { | ||
| 1895 | + imgFrame.show(); | ||
| 1896 | + } | ||
| 1897 | + imgElem.up().up().up().addClassName("has-avatar-icon"); | ||
| 1898 | + } | ||
| 1899 | + | ||
| 1900 | + if (resp.record) { | ||
| 1901 | + if (resp.record.imAvailability !== undefined && | ||
| 1902 | + resp.record.imAvailability !== null && | ||
| 1903 | + resp.record.imAvailability !== IMName.NO_PRESENCE) { | ||
| 1904 | + Mojo.Log.info("imAvailability = ", resp.record.imAvailability); | ||
| 1905 | + var imPresence; | ||
| 1906 | + switch (resp.record.imAvailability) { | ||
| 1907 | + case IMName.BUSY: | ||
| 1908 | + imPresence = 'status-busy'; | ||
| 1909 | + break; | ||
| 1910 | + case IMName.IDLE: | ||
| 1911 | + imPresence = 'status-idle'; | ||
| 1912 | + break; | ||
| 1913 | + case IMName.ONLINE: | ||
| 1914 | + imPresence = 'status-available'; | ||
| 1915 | + break; | ||
| 1916 | + default: | ||
| 1917 | + imPresence = 'status-offline'; | ||
| 1918 | + } | ||
| 1919 | + var imgElem = this.controller.get(presenceId); | ||
| 1920 | + imgElem.addClassName(imPresence); | ||
| 1921 | + imgElem.show(); | ||
| 1922 | + } | ||
| 1923 | + } | ||
| 1924 | + }, | ||
| 1925 | + | ||
| 1926 | + folderAndAccountDetails: function(resp) { | ||
| 1927 | + // this gives us the following properties folder, account, login, protocol: EAS|IMAP|POP3} | ||
| 1928 | + this.account = resp; | ||
| 1929 | + // Add the email id to the account info because it will be used by the moveto scene | ||
| 1930 | + this.account.emailId = this.data.id; | ||
| 1931 | + var assistant = Mojo.Controller.getAppController().assistant; | ||
| 1932 | + assistant.notificationAssistant.clear(resp.account, resp.folder, this.data.id); | ||
| 1933 | + assistant.clearDebounce('m'+this.data.id); | ||
| 1934 | + }, | ||
| 1935 | + | ||
| 1936 | + updateRecipientStatus: function() { | ||
| 1937 | + EmailRecipient.getDetails(this.controller, this.data.senderDetails.address, this.displayContactAvatarAndPresence.bind(this, 'email-sender', null)); | ||
| 1938 | + | ||
| 1939 | + if (this.data.onlyRecipients !== undefined) { | ||
| 1940 | + var theThis = this; | ||
| 1941 | + this.data.onlyRecipients.each(function(r) { | ||
| 1942 | + EmailRecipient.getDetails(theThis.controller, r.address, theThis.displayContactAvatarAndPresence.bind(theThis, 'recip-'+r.id, r.id)); | ||
| 1943 | + }); | ||
| 1944 | + } | ||
| 1945 | + }, | ||
| 1946 | + | ||
| 1947 | + handleSenderTap: function(event) { | ||
| 1948 | + this.showSenderContactDetails(event); | ||
| 1949 | + }, | ||
| 1950 | + | ||
| 1951 | + showSenderContactDetails: function(event) { | ||
| 1952 | + if (this.data.fromID) { | ||
| 1953 | + EmailRecipient.launchContactDetails(this.controller, this.data.fromID); | ||
| 1954 | + } else { | ||
| 1955 | + var displayName = this.data.displayName; | ||
| 1956 | + // if the display name is the email address it isn't really the person's name | ||
| 1957 | + if (displayName === this.data.senderDetails.address) { | ||
| 1958 | + displayName = ""; | ||
| 1959 | + } | ||
| 1960 | + EmailRecipient.addToContacts(this.controller, this.data.senderDetails.address, displayName); | ||
| 1961 | + } | ||
| 1962 | + }, | ||
| 1963 | + | ||
| 1964 | + handleRecipientListSelect: function(event) { | ||
| 1965 | + var targetRow = this.controller.get(event.target); | ||
| 1966 | + if (!targetRow.hasClassName('email-recipient')) { | ||
| 1967 | + targetRow = targetRow.up('div.email-recipient'); | ||
| 1968 | + } | ||
| 1969 | + | ||
| 1970 | + if (targetRow) { | ||
| 1971 | + var contactId = targetRow.readAttribute('contactid'); | ||
| 1972 | + if (contactId && contactId > 0) { | ||
| 1973 | + EmailRecipient.launchContactDetails(this.controller, contactId); | ||
| 1974 | + } else { | ||
| 1975 | + var address = targetRow.readAttribute('address'); | ||
| 1976 | + var displayName = targetRow.readAttribute('displayname'); | ||
| 1977 | + displayName = displayName.escapeHTML(); | ||
| 1978 | + EmailRecipient.addToContacts(this.controller, address, displayName); | ||
| 1979 | + } | ||
| 1980 | + } | ||
| 1981 | + }, | ||
| 1982 | + | ||
| 1983 | + showHideRecipients: function(event) { | ||
| 1984 | + this.recipsDrawer.element.mojo.setOpenState(!this.recipsDrawer.element.mojo.getOpenState()); | ||
| 1985 | + this.controller.get('email_recipients_compressed_list').toggle(); | ||
| 1986 | + this.controller.get('email_recipients_compressed_count').toggle(); | ||
| 1987 | + }, | ||
| 1988 | + | ||
| 1989 | + messageDetailsUpdated: function(resp) { | ||
| 1990 | + if (this.gotFirstResponse === false) { | ||
| 1991 | + this.gotFirstResponse = true; | ||
| 1992 | + this.renderMessage(resp); | ||
| 1993 | + } else { | ||
| 1994 | + Mojo.Log.info("renderMessage: waiting for message body. isFullyLoaded=", resp.isFullyLoaded); | ||
| 1995 | + if (resp.isFullyLoaded == "true") { | ||
| 1996 | + if (this.waitingForMessageBodyTimeout !== undefined) { | ||
| 1997 | + clearTimeout(this.waitingForMessageBodyTimeout); | ||
| 1998 | + this.waitingForMessageBodyTimeout = undefined; | ||
| 1999 | + } | ||
| 2000 | + // Add the email body to the stored data model | ||
| 2001 | + this.data.textURI = resp.textURI; | ||
| 2002 | + this.data.text = resp.text; | ||
| 2003 | + this.renderMessageBody(resp); | ||
| 2004 | + } | ||
| 2005 | + | ||
| 2006 | + // POP doesn't know it has attachments until it has downloaded the full envelope | ||
| 2007 | + // so use the new attachment list if one there doesn't already exist | ||
| 2008 | + if ((!this.data.attachments || this.data.attachments.length === 0) && | ||
| 2009 | + resp.attachments && EmailFlags.hasAttachment(resp.flags)) { | ||
| 2010 | + this.data.attachments = resp.attachments; | ||
| 2011 | + this.renderMessageAttachments(resp.attachments); | ||
| 2012 | + } | ||
| 2013 | + } | ||
| 2014 | + }, | ||
| 2015 | + | ||
| 2016 | + // This is a special function that is only called when the scene is first launched | ||
| 2017 | + // and activate() occurs before the mailservice has time to respond with the full | ||
| 2018 | + // email data. | ||
| 2019 | + prerenderMessage: function(resp) { | ||
| 2020 | + this.data.prerenderData = false; // only want to prerender email once | ||
| 2021 | + Mojo.Log.info("prerenderMessage ", resp.id); | ||
| 2022 | + | ||
| 2023 | + if ((resp.flags & EmailFlags.flaggedBit) !== 0) { | ||
| 2024 | + resp.flagged = "starred"; | ||
| 2025 | + } | ||
| 2026 | + | ||
| 2027 | + //convert the timestamp into a Date | ||
| 2028 | + var theDate = new Date(parseInt(resp.timeStamp)); | ||
| 2029 | + resp.formattedDate = Mojo.Format.formatDate(theDate, {date:'medium', time:'short'}); | ||
| 2030 | + resp.meridiem = ""; | ||
| 2031 | + | ||
| 2032 | + var content = Mojo.View.render({template: 'message/message_from', object:resp}); | ||
| 2033 | + this.controller.get('email_from').update(content); | ||
| 2034 | + //subject | ||
| 2035 | + resp.priority = Email.getPriorityClass(resp.priority); | ||
| 2036 | + content = Mojo.View.render({template: 'message/message_subject', object: resp}); | ||
| 2037 | + this.controller.get('email_subject').update(content); | ||
| 2038 | + }, | ||
| 2039 | + | ||
| 2040 | + renderMessage: function(resp) { | ||
| 2041 | + var content; | ||
| 2042 | + Mojo.Log.info("renderMessage ", resp.id); | ||
| 2043 | + this.data = resp; | ||
| 2044 | + | ||
| 2045 | + // Set the "read" flag if need be | ||
| 13 | @@ -272,9 +272,16 @@ var MessageAssistant = Class.create({ | ||
| 14 | this.data = resp; | ||
| 15 | |||
| 16 | // Set the "read" flag if need be | ||
| 2046 | 17 | + /* | |
| 2047 | + if (!EmailFlags.isRead(resp.flags)) { | ||
| 2048 | + Email.setRead(resp.id, true); | ||
| 2049 | + } | ||
| 18 | if (!EmailFlags.isRead(resp.flags)) { | ||
| 19 | Email.setRead(resp.id, true); | ||
| 20 | } | ||
| 2050 | 21 | + */ | |
| 2051 | 22 | + if (EmailFlags.isRead(resp.flags)) { | |
| 2052 | 23 | + this.markUnreadMenuItem.label = MessageAssistant.kAppMenuMarkUnread; | |
| 2053 | 24 | + } else { | |
| 2054 | 25 | + this.markUnreadMenuItem.label = MessageAssistant.kAppMenuMarkRead; | |
| 2055 | 26 | + } | |
| 2056 | + | ||
| 2057 | + // Very first thing to do with recipients is fix them up for the address picker. | ||
| 2058 | + EmailRecipient.addAddressPickerFields(resp.recipients); | ||
| 2059 | + | ||
| 2060 | + var attachments = resp.attachments; | ||
| 2061 | + | ||
| 2062 | + if (resp.displayName) { | ||
| 2063 | + resp.displayName = resp.displayName.escapeHTML(); | ||
| 2064 | + } | ||
| 2065 | + | ||
| 2066 | + if (this.data.summary == null || this.data.summary.length === 0) { | ||
| 2067 | + this.data.summary = $L("Untitled message"); | ||
| 2068 | + } else { | ||
| 2069 | + resp.summary = resp.summary.escapeHTML(); | ||
| 2070 | + } | ||
| 2071 | + | ||
| 2072 | + if ((resp.flags & EmailFlags.flaggedBit) !== 0) { | ||
| 2073 | + resp.flagged = "starred"; | ||
| 2074 | + this.markSetFlagMenuItem.label = MessageAssistant.kAppMenuClearFlag; | ||
| 2075 | + } else { | ||
| 2076 | + this.markSetFlagMenuItem.label = MessageAssistant.kAppMenuSetFlag; | ||
| 2077 | + } | ||
| 2078 | + | ||
| 2079 | + //text -- if it is fully loaded then render it (need to check for string "true" since that's what's coming in json). | ||
| 2080 | + if (this.data.isFullyLoaded == "true") { | ||
| 2081 | + this.renderMessageBody(this.data); | ||
| 2082 | + } else { | ||
| 2083 | + this.waitForMessageBody(); | ||
| 2084 | + } | ||
| 2085 | + | ||
| 2086 | + //convert the timestamp into a Date | ||
| 2087 | + //February 15, 2008 - 12:57 PM | ||
| 2088 | + var theDate = new Date(parseInt(resp.timeStamp)); | ||
| 2089 | + resp.formattedDate = Mojo.Format.formatDate(theDate, {date:'medium', time:'short'}); | ||
| 2090 | + resp.meridiem = ""; //theDate.toString($L('t')); | ||
| 2091 | + | ||
| 2092 | + content = Mojo.View.render({template: 'message/message_from', object:resp}); | ||
| 2093 | + this.controller.get('email_from').update(content); | ||
| 2094 | + //subject | ||
| 2095 | + resp.priority = Email.getPriorityClass(resp.priority); | ||
| 2096 | + content = Mojo.View.render({template: 'message/message_subject', object: resp}); | ||
| 2097 | + this.controller.get('email_subject').update(content); | ||
| 2098 | + | ||
| 2099 | + this.controller.get('previous_email').observe(Mojo.Event.tap, this.boundGotoNextEmailNewer); | ||
| 2100 | + this.controller.get('next_email').observe(Mojo.Event.tap, this.boundGotoNextEmailOlder); | ||
| 2101 | + | ||
| 2102 | + //recipients | ||
| 2103 | + this.renderMessageRecipients(resp); | ||
| 2104 | + | ||
| 2105 | + if (EmailFlags.isMeetingRequest(resp.flags)) { | ||
| 2106 | + var invite = new Object(); | ||
| 2107 | + if (resp.whenStart) { | ||
| 2108 | + var startDate = new Date(parseInt(resp.whenStart)); | ||
| 2109 | + var dateFormat = $L('EEE, MMM d'); | ||
| 2110 | + var whenObject = { | ||
| 2111 | + date: Mojo.Format.formatDate(startDate, {date:dateFormat}), | ||
| 2112 | + startTime: Mojo.Format.formatDate(startDate, {time:'short'}), | ||
| 2113 | + endTime: Mojo.Format.formatDate(new Date(parseInt(resp.whenEnd)), {time:'short'}) | ||
| 2114 | + }; | ||
| 2115 | + invite.when = $L("#{date}, #{startTime} - #{endTime}").interpolate(whenObject); | ||
| 2116 | + } else { | ||
| 2117 | + // Service used to format the date. That doesn't work for too many reasons | ||
| 2118 | + invite.when = $L("#{when}").interpolate(resp); //TODO parse this and put in local date format | ||
| 2119 | + } | ||
| 2120 | + if (resp.busyStatus === 0) { | ||
| 2121 | + // Maybe change the style here | ||
| 2122 | + invite.conflict = $L("Conflicts with another event"); | ||
| 2123 | + } | ||
| 2124 | + invite.where = $L("#{where}").interpolate(resp).escapeHTML(); | ||
| 2125 | + | ||
| 2126 | + content = Mojo.View.render({template: 'message/meeting_invitation', object: invite}); | ||
| 2127 | + this.controller.get('email-readview-invitations').update(content); | ||
| 2128 | + | ||
| 2129 | + this.controller.get('invite-accept').observe(Mojo.Event.tap, this.boundHandleInviteResponseAccept); | ||
| 2130 | + this.controller.get('invite-tentative').observe(Mojo.Event.tap, this.boundHandleInviteResponseTentative); | ||
| 2131 | + this.controller.get('invite-decline').observe(Mojo.Event.tap, this.boundHandleInviteResponseDecline); | ||
| 2132 | + } | ||
| 2133 | + else if (EmailFlags.isMeetingCancel(resp.flags)) { | ||
| 2134 | + content = Mojo.View.render({template: 'message/meeting_cancellation', object: {}}); | ||
| 2135 | + this.controller.get('email-readview-invitations').update(content); | ||
| 2136 | + this.controller.get('invite-remove').observe(Mojo.Event.tap, this.boundHandleInviteResponseRemove); | ||
| 2137 | + } | ||
| 2138 | + else { | ||
| 2139 | + this.controller.get('email-readview-invitations').update(""); | ||
| 2140 | + } | ||
| 2141 | + | ||
| 2142 | + // Attachments - some may be in the HTML body, so only show the attachments area if there | ||
| 2143 | + // is something in the attachments array | ||
| 2144 | + if (attachments && EmailFlags.hasAttachment(this.data.flags)) { | ||
| 2145 | + this.renderMessageAttachments(attachments); | ||
| 2146 | + } else { | ||
| 2147 | + // If no attachments, make sure old UI is cleaned out. | ||
| 2148 | + this.controller.get('email-readview-attachments-block').hide(); | ||
| 2149 | + this.emailPicturesBlock.update(""); | ||
| 2150 | + } | ||
| 2151 | + | ||
| 2152 | + // Ensure the whiteness is at least tall enough to fill the screen. | ||
| 2153 | + var contentContainer = this.controller.get('email-readview-content-container'); | ||
| 2154 | + var po = contentContainer.positionedOffset(); | ||
| 2155 | + var minHeight = (this.controller.window.innerHeight - po.top) + 'px'; | ||
| 2156 | + contentContainer.setStyle({'min-height':minHeight}) | ||
| 2157 | + | ||
| 2158 | + // Got the message details so say we're ready to render | ||
| 2159 | + if (this.delayActivate === true) { | ||
| 2160 | + this.delayActivate = false; | ||
| 2161 | + if (this.readyToActivateCallback !== undefined) { | ||
| 2162 | + this.readyToActivateCallback(); | ||
| 2163 | + this.readyToActivateCallback = undefined; | ||
| 2164 | + } | ||
| 2165 | + } | ||
| 2166 | + | ||
| 2167 | + // Get details about the next and previous emails to know where the user can navigate. | ||
| 2168 | + // NOTE: this needs to be after message_subject is rendered | ||
| 2169 | + this.controller.serviceRequest(Email.identifier, { | ||
| 2170 | + method: 'getNextMessages', | ||
| 2171 | + parameters: {'message':this.data.id, 'folder': this.folderId }, | ||
| 2172 | + onSuccess: this.handleNextMessagesResponse.bind(this), | ||
| 2173 | + onFailure: function(response) { Mojo.Log.error("getNextMessages failed "+Object.toJSON(response)); } | ||
| 2174 | + }); | ||
| 2175 | + | ||
| 2176 | + if (this.transition !== null) { | ||
| 2177 | + this.transition.run(); | ||
| 2178 | + this.transition.cleanup(); | ||
| 2179 | + this.transition = null; | ||
| 2180 | + } | ||
| 2181 | + }, | ||
| 2182 | + | ||
| 2183 | + renderMessageRecipients: function(resp) { | ||
| 2184 | + var recips = resp.recipients; | ||
| 2185 | + this.data.onlyRecipients = []; | ||
| 2186 | + this.data.senderDetails = {}; | ||
| 2187 | + var content = null; | ||
| 2188 | + if (recips) { | ||
| 2189 | + var recipTypes; | ||
| 2190 | + if (EmailFlags.isMeetingType(resp.flags)) { | ||
| 2191 | + recipTypes = [ $L("From"), $L("Required"), $L("Optional"), $L("Bcc"), $L("From") ]; | ||
| 2192 | + } else { | ||
| 2193 | + recipTypes = [ $L("From"), $L("To"), $L("Cc"), $L("Bcc"), $L("From") ]; | ||
| 2194 | + } | ||
| 2195 | + | ||
| 2196 | + var theThis = this; | ||
| 2197 | + var prevRecp = {}; // This is used to determine when to display To/Cc/Bcc divider | ||
| 2198 | + recips.each(function(r) { | ||
| 2199 | + if(recipTypes[r.role] !== undefined) { | ||
| 2200 | + if (r.role === EmailRecipient.roleTo || r.role === EmailRecipient.roleCc || r.role === EmailRecipient.roleBcc) { | ||
| 2201 | + r.roleStr = recipTypes[r.role]; | ||
| 2202 | + if (r.role != prevRecp.role) { | ||
| 2203 | + r.rowDisplayRole = "show"; | ||
| 2204 | + r.hasDivider = "has-divider"; | ||
| 2205 | + prevRecp.hideLast = "last"; | ||
| 2206 | + } | ||
| 2207 | + theThis.data.onlyRecipients.push(r); | ||
| 2208 | + EmailRecipient.getDetails(theThis.controller, r.address, theThis.displayContactAvatarAndPresence.bind(theThis, 'recip-'+r.id, r.id)); | ||
| 2209 | + prevRecp = r; | ||
| 2210 | + } | ||
| 2211 | + // roleReplyTo can overwrite the senderDetails because it takes precidence over roleFrom | ||
| 2212 | + else if (r.role === EmailRecipient.roleReplyTo) { | ||
| 2213 | + theThis.data.senderDetails = r; | ||
| 2214 | + } | ||
| 2215 | + // roleFrom should not overwrite the senderDetails because roleReplyTo takes precidence | ||
| 2216 | + else if (r.role === EmailRecipient.roleFrom && theThis.data.senderDetails.address === undefined) { | ||
| 2217 | + theThis.data.senderDetails = r; | ||
| 2218 | + } | ||
| 2219 | + } | ||
| 2220 | + }); | ||
| 2221 | + | ||
| 2222 | + if (this.data.senderDetails.address !== undefined) { | ||
| 2223 | + // Get the contact ID for the sender of the email | ||
| 2224 | + EmailRecipient.getDetails(this.controller, this.data.senderDetails.address, this.displayContactAvatarAndPresence.bind(this, 'email-sender', null)); | ||
| 2225 | + } | ||
| 2226 | + | ||
| 2227 | + if (this.data.onlyRecipients.length > 0) { | ||
| 2228 | + var recipElem = this.controller.get('email_recipients'); | ||
| 2229 | + content = Mojo.View.render({ | ||
| 2230 | + collection: this.data.onlyRecipients, | ||
| 2231 | + template: 'message/message_recips' | ||
| 2232 | + }); | ||
| 2233 | + recipElem.update(content); | ||
| 2234 | + | ||
| 2235 | + var recipsSummary = { count:0, to:[], cc:[], bcc:[] }; | ||
| 2236 | + this.data.onlyRecipients.each(function(r) { | ||
| 2237 | + if (r.role === EmailRecipient.roleTo) { | ||
| 2238 | + recipsSummary.to.push(r.displayName); | ||
| 2239 | + recipsSummary.count++; | ||
| 2240 | + } else if (r.role === EmailRecipient.roleCc) { | ||
| 2241 | + recipsSummary.cc.push(r.displayName); | ||
| 2242 | + recipsSummary.count++; | ||
| 2243 | + } else if (r.role === EmailRecipient.roleBcc) { | ||
| 2244 | + recipsSummary.bcc.push(r.displayName); | ||
| 2245 | + recipsSummary.count++; | ||
| 2246 | + } | ||
| 2247 | + }); | ||
| 2248 | + | ||
| 2249 | + if (recipsSummary.count > 0) { | ||
| 2250 | + recipsSummary.displayTo = "none"; | ||
| 2251 | + recipsSummary.displayCc = "none"; | ||
| 2252 | + recipsSummary.displayBcc = "none"; | ||
| 2253 | + if (recipsSummary.to.length > 0 && recipsSummary.cc.length > 0) { | ||
| 2254 | + recipsSummary.displayTo = "inline"; | ||
| 2255 | + recipsSummary.displayCc = "inline"; | ||
| 2256 | + recipsSummary.toList = recipsSummary.to.join(', '); | ||
| 2257 | + recipsSummary.ccList = recipsSummary.cc.join(', '); | ||
| 2258 | + } else if (recipsSummary.to.length > 0) { | ||
| 2259 | + recipsSummary.displayTo = "inline"; | ||
| 2260 | + recipsSummary.toList = recipsSummary.to.join(', '); | ||
| 2261 | + } else if (recipsSummary.cc.length > 0) { | ||
| 2262 | + recipsSummary.displayCc = "inline"; | ||
| 2263 | + recipsSummary.ccList = recipsSummary.cc.join(', '); | ||
| 2264 | + } else if (recipsSummary.bcc.length > 0) { | ||
| 2265 | + recipsSummary.displayBcc = "inline"; | ||
| 2266 | + recipsSummary.bccList = recipsSummary.bcc.join(', '); | ||
| 2267 | + } | ||
| 2268 | + | ||
| 2269 | + if (recipsSummary.count === 1) { | ||
| 2270 | + recipsSummary.recipientCount = $L("1 recipient"); | ||
| 2271 | + } else { | ||
| 2272 | + recipsSummary.recipientCount = $L("#{count} recipients").interpolate(recipsSummary); | ||
| 2273 | + } | ||
| 2274 | + | ||
| 2275 | + content = Mojo.View.render({template: 'message/message_recips_compressed', object: recipsSummary }); | ||
| 2276 | + this.recipientController = this.controller.get('email_recipients_controller') | ||
| 2277 | + this.recipientController.update(content); | ||
| 2278 | + // Observe the row since that is the entire height and width of the tappable area | ||
| 2279 | + this.recipientController.up(".palm-row").observe(Mojo.Event.tap, this.boundShowHideRecipients, true); | ||
| 2280 | + } | ||
| 2281 | + } | ||
| 2282 | + } | ||
| 2283 | + | ||
| 2284 | + // If there were no recipients, then display the default "no recips" | ||
| 2285 | + if (content === null) { | ||
| 2286 | + Mojo.Log.info("displaying 'Only BCC recipients'"); | ||
| 2287 | + var renderParams = { | ||
| 2288 | + template: 'message/message_recips_compressed', | ||
| 2289 | + object: {onlyBccRecipient: $L("Only BCC recipients"), displayTo: "none", displayCc: "none", displayBcc: "none" } | ||
| 2290 | + }; | ||
| 2291 | + this.controller.get('email_recipients_controller').update(Mojo.View.render(renderParams)); | ||
| 2292 | + } | ||
| 2293 | + }, | ||
| 2294 | + | ||
| 2295 | + processTextProperty: function(data) { | ||
| 2296 | + // If it is an html email, it starts with "<!DOCTYPE" or "<html" some simple html tag | ||
| 2297 | + if (!data.isHtml) { | ||
| 2298 | + //console.log("******* NO MATCH *********") | ||
| 2299 | + // Plain text needs to replace the carriage returns with html line-break tags | ||
| 2300 | + data.text = data.text.escapeHTML().gsub("\n","<br>"); | ||
| 2301 | + } else { | ||
| 2302 | + //console.log("******* MATCH *********") | ||
| 2303 | + data.text = data.text.stripScripts(); | ||
| 2304 | + } | ||
| 2305 | + }, | ||
| 2306 | + | ||
| 2307 | + renderMessageBody: function(data) { | ||
| 2308 | + if (data.isFullyLoaded != "true") { | ||
| 2309 | + Mojo.Log.error("renderMessageBody aborted because data.isFullyLoaded == ", data.isFullyLoaded) | ||
| 2310 | + return; | ||
| 2311 | + } | ||
| 2312 | + | ||
| 2313 | + this.hideNoBodyUI(); | ||
| 2314 | + | ||
| 2315 | + if (data.textURI && this.webview.mojo.openURL) { | ||
| 2316 | + this.controller.get('email_text').hide(); | ||
| 2317 | + | ||
| 2318 | + try { | ||
| 2319 | + Mojo.Log.breadcrumb("rendering URI " + data.textURI); | ||
| 2320 | + this.webview.mojo.setEnableJavaScript(false); | ||
| 2321 | + this.webview.mojo.openURL("file://" + data.textURI); | ||
| 2322 | + } catch (e) { | ||
| 2323 | + Mojo.Log.logException(e, 'renderMessageBody openUrl'); | ||
| 2324 | + } | ||
| 2325 | + | ||
| 2326 | + // If the service didn't supply the text to use for replying to an email, request it now. | ||
| 2327 | + if (!data.text) { | ||
| 2328 | + var processTextProperty = this.processTextProperty; | ||
| 2329 | + this.controller.serviceRequest(Message.identifier, { | ||
| 2330 | + method: 'messageFileText', | ||
| 2331 | + parameters: { 'textURI':data.textURI }, | ||
| 2332 | + onSuccess: function(resp) { | ||
| 2333 | + data.text = resp.text; | ||
| 2334 | + processTextProperty(data); | ||
| 2335 | + }, | ||
| 2336 | + onFailure: function() { Mojo.Log.error("messageFileText failed for textURI", data.textURI) } | ||
| 2337 | + }); | ||
| 2338 | + } else { | ||
| 2339 | + // Defer b/c this can be done after the email is rendered | ||
| 2340 | + this.processTextProperty.defer(data); | ||
| 2341 | + } | ||
| 2342 | + } else { | ||
| 2343 | + Mojo.Log.warn("WARNING: EMAIL using plain text"); | ||
| 2344 | + var adapter = this.controller.get('email_body_text_outer'); | ||
| 2345 | + if (adapter == null) { | ||
| 2346 | + adapter = this.controller.get('email_body_text'); | ||
| 2347 | + } | ||
| 2348 | + adapter.hide(); | ||
| 2349 | + var emailBody = this.controller.get('email_text'); | ||
| 2350 | + // Strip out all scripts since they can do dangerous things | ||
| 2351 | + data.text = data.text.stripScripts(); | ||
| 2352 | + // Since this is plain text, need to replace the carriage returns with html line-break tags | ||
| 2353 | + data.text = data.text.gsub("\n","<br>"); | ||
| 2354 | + data.styles = "width:"+this.controller.window.innerWidth+"px;"; | ||
| 2355 | + var content = Mojo.View.render({ | ||
| 2356 | + template: 'message/message_text', | ||
| 2357 | + object: data | ||
| 2358 | + }); | ||
| 2359 | + emailBody.update(content); | ||
| 2360 | + emailBody.show(); | ||
| 2361 | + } | ||
| 2362 | + | ||
| 2363 | + this.webview.mojo.focus(); | ||
| 2364 | + }, | ||
| 2365 | + | ||
| 2366 | + renderMessageAttachments: function(attachments) { | ||
| 2367 | + // Show the div containing the attachments. For multiple attachments, also | ||
| 2368 | + // show the expand/collapse controller | ||
| 2369 | + this.controller.get('email-readview-attachments-block').show(); | ||
| 2370 | + | ||
| 2371 | + var picturesList = []; | ||
| 2372 | + var names = undefined; | ||
| 2373 | + attachments.each(function(a) { | ||
| 2374 | + a.displayName = a.displayName.escapeHTML(); | ||
| 2375 | + if (names === undefined) { | ||
| 2376 | + names = a.displayName.substring(0); // copy of the name | ||
| 2377 | + } else { | ||
| 2378 | + names += ", " + a.displayName; | ||
| 2379 | + } | ||
| 2380 | + // Icons | ||
| 2381 | + Attachments.processFileObject(a); | ||
| 2382 | + // Picture to be displayed | ||
| 2383 | + if (a.iconType == "type-image") { | ||
| 2384 | + var extension = a.extension.toLowerCase(); | ||
| 2385 | + if (extension === ".jpg" || extension === ".jpeg" || extension === ".png") { | ||
| 2386 | + a.fixeduri = "file:///var/luna/data/extractfs/" + a.uri + ":0:0:320:240:3"; | ||
| 2387 | + } else { | ||
| 2388 | + a.fixeduri = a.uri; | ||
| 2389 | + } | ||
| 2390 | + picturesList.push(a); | ||
| 2391 | + } else { | ||
| 2392 | + a.displayImage = "display:none"; | ||
| 2393 | + } | ||
| 2394 | + | ||
| 2395 | + // Download % | ||
| 2396 | + if (a.uri) { | ||
| 2397 | + a.display = "display: none;"; | ||
| 2398 | + a.download = ""; | ||
| 2399 | + } else { | ||
| 2400 | + a.download = "show-download-icon"; | ||
| 2401 | + a.display = "display: none;"; | ||
| 2402 | + } | ||
| 2403 | + }); | ||
| 2404 | + | ||
| 2405 | + // Only show the special "this file and N others" if there's more than 1 attachment | ||
| 2406 | + if (attachments.length > 1) { | ||
| 2407 | + // Setup the attachment compressed view | ||
| 2408 | + var content = Mojo.View.render({ | ||
| 2409 | + object: { displayName:names, count:attachments.length }, | ||
| 2410 | + template: 'message/message_attachments_compressed' | ||
| 2411 | + }); | ||
| 2412 | + this.attachmentsShowElem.update(content); | ||
| 2413 | + } | ||
| 2414 | + | ||
| 2415 | + content = Mojo.View.render({ | ||
| 2416 | + collection: attachments, | ||
| 2417 | + template: 'message/message_attachments' | ||
| 2418 | + }); | ||
| 2419 | + this.controller.get('email-readview-attachments-list').update(content); | ||
| 2420 | + | ||
| 2421 | + // Attachment pictures | ||
| 2422 | + if (picturesList.length > 0) { | ||
| 2423 | + content = Mojo.View.render({ | ||
| 2424 | + collection: picturesList, | ||
| 2425 | + template: 'message/message_pictures' | ||
| 2426 | + }); | ||
| 2427 | + this.emailPicturesBlock.update(content); | ||
| 2428 | + } else { | ||
| 2429 | + this.emailPicturesBlock.update(""); | ||
| 2430 | + } | ||
| 2431 | + | ||
| 2432 | + // Convert any downloaded audio attachments to AudioTag controls | ||
| 2433 | + attachments.each(function(a) { | ||
| 2434 | + if (a.uri !== undefined) { | ||
| 2435 | + this.setupAudioTag(a); | ||
| 2436 | + } | ||
| 2437 | + }.bind(this)); | ||
| 2438 | + | ||
| 2439 | + // | ||
| 2440 | + // Now that the contents of the list are ready, compute heights and setup the "drawer" | ||
| 2441 | + // | ||
| 2442 | + this.attachmentList = this.controller.get('attachlist-list1'); | ||
| 2443 | + this.attachmentList.setStyle({height:'auto'}); // make sure the height below is the full height | ||
| 2444 | + this.attachmentListHeight = parseInt(this.attachmentList.getHeight(), 10); | ||
| 2445 | + | ||
| 2446 | + // If the list contains only 1 item so it isn't considered as "shown" | ||
| 2447 | + this.attachmentListShown = (attachments.length > 1); | ||
| 2448 | + if (this.attachmentListShown) { | ||
| 2449 | + // Initially hide the attachments list | ||
| 2450 | + this.attachmentListShown = false; | ||
| 2451 | + this.attachmentList.setStyle({'height':'46px'}); | ||
| 2452 | + this.attachmentList.hide(); | ||
| 2453 | + this.attachmentsShowElem.show(); | ||
| 2454 | + } else { | ||
| 2455 | + this.attachmentsShowElem.hide(); | ||
| 2456 | + this.attachmentList.show(); | ||
| 2457 | + } | ||
| 2458 | + }, | ||
| 2459 | + | ||
| 2460 | + setupAudioTag: function(a) { | ||
| 2461 | + var success = false; | ||
| 2462 | + if (a.uri !== undefined && a.mimeType.startsWith("audio")) { | ||
| 2463 | + var audioElement = this.controller.get("progress_" + a.id); | ||
| 2464 | + try { | ||
| 2465 | + audioElement.show(); | ||
| 2466 | + var audioTag = AudioTag.extendElement(audioElement, this.controller, a.uri); | ||
| 2467 | + audioTag.autoplay = false; | ||
| 2468 | + this.controller.get("adetails_" + a.id).hide(); | ||
| 2469 | + success = true; | ||
| 2470 | + } catch (e) { | ||
| 2471 | + audioElement.hide(); | ||
| 2472 | + } | ||
| 2473 | + } | ||
| 2474 | + return success; | ||
| 2475 | + }, | ||
| 2476 | + | ||
| 2477 | + waitForMessageBody: function() { | ||
| 2478 | + // If the transport can't retrieve the message in a reasonable amount of time, error out | ||
| 2479 | + this.waitingForMessageBodyTimeout = this.waitMessageError.bind(this).delay(45); | ||
| 2480 | + this.showNoBodyUI(); | ||
| 2481 | + }, | ||
| 2482 | + | ||
| 2483 | + waitMessageError: function(resp) { | ||
| 2484 | + if (this.messageSubscription) { | ||
| 2485 | + this.messageSubscription.cancel(); | ||
| 2486 | + this.messageSubscription = null; | ||
| 2487 | + } | ||
| 2488 | + Mojo.Log.error("waitMessageError", Object.toJSON(resp)); | ||
| 2489 | + | ||
| 2490 | + // Waiting for message body means the message exists, but the body | ||
| 2491 | + // isn't yet on device. If the error occured before even waiting for | ||
| 2492 | + // the body, then popScene out to the previous scene because this | ||
| 2493 | + // email doesn't even exists anymore. | ||
| 2494 | + if (this.waitingForMessageBodyTimeout === undefined) { | ||
| 2495 | + // This should only occur if the email ID doesn't exist so go back to the previous scene | ||
| 2496 | + Mojo.Log.error("popping the message scene because message doesn't exists. ID=", this.data.id); | ||
| 2497 | + this.controller.stageController.popScene(resp); | ||
| 2498 | + } else { | ||
| 2499 | + clearTimeout(this.waitingForMessageBodyTimeout); | ||
| 2500 | + this.waitingForMessageBodyTimeout = undefined; | ||
| 2501 | + this.hideNoBodyUI(); | ||
| 2502 | + | ||
| 2503 | + // Display error text | ||
| 2504 | + this.plainTextBody.update(Mojo.View.render({template: 'message/failed_to_download_err', object:{}})); | ||
| 2505 | + this.plainTextBody.show(); | ||
| 2506 | + } | ||
| 2507 | + }, | ||
| 2508 | + | ||
| 2509 | + showNoBodyUI: function() { | ||
| 2510 | + var nobodyDiv = this.controller.get('email_no_body') | ||
| 2511 | + nobodyDiv.show(); | ||
| 2512 | + this.controller.instantiateChildWidgets(nobodyDiv); | ||
| 2513 | + this.controller.get('email_no_body_spinner').mojo.start(); | ||
| 2514 | + }, | ||
| 2515 | + | ||
| 2516 | + hideNoBodyUI: function() { | ||
| 2517 | + this.controller.get('email_no_body_spinner').mojo.stop(); | ||
| 2518 | + this.controller.get('email_no_body').hide(); | ||
| 2519 | + }, | ||
| 2520 | + | ||
| 2521 | + handleToggleFavorites: function(event) { | ||
| 2522 | + // Flip the flagged bit | ||
| 2523 | + var value = true; | ||
| 2524 | + this.data.flags = this.data.flags ^ EmailFlags.flaggedBit; | ||
| 2525 | + if ((this.data.flags & EmailFlags.flaggedBit) == 0) { | ||
| 2526 | + this.controller.get('email_favorite').removeClassName("starred"); | ||
| 2527 | + this.data.flagged = ""; | ||
| 2528 | + this.markSetFlagMenuItem.label = MessageAssistant.kAppMenuSetFlag; | ||
| 2529 | + value = false; | ||
| 2530 | + } else { | ||
| 2531 | + this.controller.get('email_favorite').addClassName("starred"); | ||
| 2532 | + this.data.flagged = "starred"; | ||
| 2533 | + this.markSetFlagMenuItem.label = MessageAssistant.kAppMenuClearFlag; | ||
| 2534 | + } | ||
| 2535 | + //console.log("Setting flagged for " + this.data.id + " to " + value); | ||
| 2536 | + Email.setFlagged(this.data.id, value); | ||
| 2537 | + }, | ||
| 2538 | + | ||
| 2539 | + handleAttachmentTapped: function(event) { | ||
| 2540 | + var targetRow = this.controller.get(event.target); | ||
| 2541 | + var listDiv = targetRow; | ||
| 2542 | + if (!listDiv.hasClassName('attachment-info')) { | ||
| 2543 | + listDiv = listDiv.up('div.attachment-info'); | ||
| 2544 | + } | ||
| 2545 | + | ||
| 2546 | + if (listDiv) { | ||
| 2547 | + var attachmentUri = listDiv.getAttribute('x-uri'); | ||
| 2548 | + var attachmentMimeType = listDiv.getAttribute('x-mimetype'); | ||
| 2549 | + if (attachmentUri) { | ||
| 2550 | + if (attachmentMimeType.startsWith("audio")) { | ||
| 2551 | + // Do nothing because the AudioTag widget handles taps for audio files | ||
| 2552 | + } else if (attachmentMimeType.startsWith("image")) { | ||
| 2553 | + this.controller.stageController.pushScene('imageview', attachmentUri); | ||
| 2554 | + } else { | ||
| 2555 | + if (attachmentUri.startsWith("/")) { | ||
| 2556 | + attachmentUri = "file://" + attachmentUri; | ||
| 2557 | + } | ||
| 2558 | + //Message.launchAttachment(this.controller, attachmentUri, this.error.bind(this)); | ||
| 2559 | + Message.getResourceType(this.controller, attachmentUri, attachmentMimeType, this.gotResourceType.bind(this), this.useInternalResourceHandler.bind(this, attachmentMimeType)); | ||
| 2560 | + } | ||
| 2561 | + } else if (event.target.className === "download-cancel") { | ||
| 2562 | + this.stopAttachmentDownload(listDiv.id); | ||
| 2563 | + } else { | ||
| 2564 | + // Stop the timeout | ||
| 2565 | + if (this.hideTimeout) { | ||
| 2566 | + clearTimeout(this.hideTimeout); | ||
| 2567 | + this.hideTimeout = null; | ||
| 2568 | + } | ||
| 2569 | + this.startAttachmentDownload(listDiv.id); | ||
| 2570 | + } | ||
| 2571 | + } | ||
| 2572 | + }, | ||
| 2573 | + | ||
| 2574 | + handleImageTapped: function(event) { | ||
| 2575 | + var imgElem = this.controller.get(event.target.id); | ||
| 2576 | + var uri = imgElem.getAttribute('x-uri'); | ||
| 2577 | + this.controller.stageController.pushScene('imageview', uri); | ||
| 2578 | + }, | ||
| 2579 | + | ||
| 2580 | + /* | ||
| 2581 | + * Callback function for getResourceType | ||
| 2582 | + */ | ||
| 2583 | + gotResourceType: function(payload) { | ||
| 2584 | + //Check if this is launchable | ||
| 2585 | + if(payload.returnValue && payload.appIdByExtension) { | ||
| 2586 | + Message.launchAttachments(this.controller,payload.uri, payload.appIdByExtension, payload.mimeByExtension); | ||
| 2587 | + } else { | ||
| 2588 | + this.useInternalResourceHandler(payload.mimeByExtension, payload); | ||
| 2589 | + } | ||
| 2590 | + }, | ||
| 2591 | + | ||
| 2592 | + useInternalResourceHandler: function(mimeType, response) { | ||
| 2593 | + var type = Attachments.getIconTypeFromMimeType(mimeType); | ||
| 2594 | + if (!type) { | ||
| 2595 | + try { | ||
| 2596 | + var extensionIndex = response.uri.lastIndexOf('.'); | ||
| 2597 | + if (extensionIndex > 0) { | ||
| 2598 | + var extension = response.uri.substring(extensionIndex + 1).toLowerCase(); | ||
| 2599 | + type = Attachments.getIconTypeFromExtension(extension); | ||
| 2600 | + } | ||
| 2601 | + } catch (e) { | ||
| 2602 | + Mojo.Log.logException(e, "MessageAssistant.useInternalResourceHandler"); | ||
| 2603 | + } | ||
| 2604 | + } | ||
| 2605 | + | ||
| 2606 | + if (type === "type-image") { | ||
| 2607 | + this.controller.stageController.pushScene('imageview', response.uri); | ||
| 2608 | + } else { | ||
| 2609 | + Mojo.Log.error("Email - Attachment can't be opened!"); | ||
| 2610 | + this.controller.showAlertDialog({ | ||
| 2611 | + onChoose: function(value) {}, | ||
| 2612 | + message: $L("Cannot find an application which can open this file."), | ||
| 2613 | + choices: [ | ||
| 2614 | + {label:$L('OK'), value:'dismiss', type:'alert'} | ||
| 2615 | + ] | ||
| 2616 | + }); | ||
| 2617 | + } | ||
| 2618 | + }, | ||
| 2619 | + | ||
| 2620 | + startAttachmentDownload: function(id) { | ||
| 2621 | + Mojo.Log.info("start attachment download", id); | ||
| 2622 | + var progressbar = this.controller.get('progress_' + id); | ||
| 2623 | + if (progressbar.visible()) { | ||
| 2624 | + Mojo.Log.info("ignoring tap because attachment is already downloading"); | ||
| 2625 | + } else { | ||
| 2626 | + this.attachmentDLProgress.subs[id] = Message.loadAttachment(id, this.attachmentDownloadProgress.bind(this), this.attachmentError.bind(this, id)); | ||
| 2627 | + | ||
| 2628 | + // This makes the progressbar show up so the user gets immediate feedback. | ||
| 2629 | + this.controller.get('file_size_' + id).hide(); // showing the progress bar so hide the file size | ||
| 2630 | + this.controller.get('progress_' + id).show(); // ensures the progress bar is shown | ||
| 2631 | + // Set the initial progress to 0% | ||
| 2632 | + this.attachmentUpdateProgressbar(id, 0); | ||
| 2633 | + } | ||
| 2634 | + }, | ||
| 2635 | + | ||
| 2636 | + stopAttachmentDownload: function(id) { | ||
| 2637 | + Mojo.Log.info("stop attachment download", id); | ||
| 2638 | + this.attachmentDLProgress.clearSubscription(id); | ||
| 2639 | + Message.cancelLoadAttachment(this.controller, id); | ||
| 2640 | + | ||
| 2641 | + // This makes the progressbar show up so the user gets immediate feedback. | ||
| 2642 | + this.controller.get('file_size_' + id).show(); | ||
| 2643 | + this.controller.get('progress_' + id).hide(); | ||
| 2644 | + // Set the initial progress to 0% | ||
| 2645 | + this.attachmentUpdateProgressbar(id, 0); | ||
| 2646 | + }, | ||
| 2647 | + | ||
| 2648 | + handleInviteResponse: function(response, event) { | ||
| 2649 | + Mojo.Log.info("handleInviteResponse ", response); | ||
| 2650 | + var notificationAssistant = Mojo.Controller.getAppController().assistant.notificationAssistant; | ||
| 2651 | + notificationAssistant.handleNotification({ type:"general", message:$L("Sending invitation response") }); | ||
| 2652 | + Email.inviteResponse(this.data, response); | ||
| 2653 | + this.controller.stageController.popScene(); | ||
| 2654 | + }, | ||
| 2655 | + | ||
| 2656 | + attachmentError: function(id, err) { | ||
| 2657 | + Mojo.Log.error("handleError ", err.errorText); | ||
| 2658 | + this.stopAttachmentDownload(id); | ||
| 2659 | + var that = this; | ||
| 2660 | + var errorText; | ||
| 2661 | + if (err.errorText && err.errorText.length > 0) { | ||
| 2662 | + errorText = $L("Error downloading file. Server reports: #{errorText}").interpolate(err).escapeHTML(); | ||
| 2663 | + } else { | ||
| 2664 | + errorText = $L("Error while downloading file."); | ||
| 2665 | + } | ||
| 2666 | + | ||
| 2667 | + this.controller.showAlertDialog({ | ||
| 2668 | + onChoose: function(value) {}, | ||
| 2669 | + title: $L("Unable To Download File"), | ||
| 2670 | + message: errorText, | ||
| 2671 | + choices: [ {label:$L('OK'), value:'dismiss', type:'alert'} ] | ||
| 2672 | + }); | ||
| 2673 | + }, | ||
| 2674 | + | ||
| 2675 | + handleAttachmentDetails: function(attachment) { | ||
| 2676 | + Mojo.Log.info("handleAttachmentDetails ", attachment.id); | ||
| 2677 | + | ||
| 2678 | + // Update the uri for this attachment now that we got one. | ||
| 2679 | + this.data.attachments.each(function(a) { | ||
| 2680 | + if (a.id == attachment.id) { | ||
| 2681 | + a.uri = attachment.uri; | ||
| 2682 | + $break; | ||
| 2683 | + } | ||
| 2684 | + }); | ||
| 2685 | + | ||
| 2686 | + // For some reason the id needs to be a string so using toString(). | ||
| 2687 | + var elem = this.controller.get((attachment.id).toString()); | ||
| 2688 | + var newUri = attachment.uri; | ||
| 2689 | + elem.writeAttribute('x-uri', newUri); | ||
| 2690 | + elem.writeAttribute('x-mimetype', attachment.mimeType); | ||
| 2691 | + | ||
| 2692 | + var audioSetup = this.setupAudioTag(attachment); | ||
| 2693 | + if (audioSetup) { | ||
| 2694 | + // The height of the inline audio player is different so need to recalc the list height | ||
| 2695 | + this.attachmentList.setStyle({height:'auto'}); // make sure the height below is the full height | ||
| 2696 | + this.attachmentListHeight = parseInt(this.attachmentList.getHeight(), 10); | ||
| 2697 | + } else { | ||
| 2698 | + var imgElem = this.controller.get('picture_'+attachment.id); | ||
| 2699 | + if (imgElem) { | ||
| 2700 | + Mojo.Log.info("set img src=", newUri); | ||
| 2701 | + imgElem.writeAttribute('x-uri', newUri); | ||
| 2702 | + // Following uri uses extractfs to scale the image to fit 320x240. | ||
| 2703 | + // This fixes problems with extremely large images causing the UI to chug. | ||
| 2704 | + Attachments.processFileObject(attachment); | ||
| 2705 | + var extension = attachment.extension.toLowerCase(); | ||
| 2706 | + if (extension === ".jpg" || extension === ".jpeg" || extension === ".png") { | ||
| 2707 | + imgElem.src = "file:///var/luna/data/extractfs/"+newUri+":0:0:320:240:3"; | ||
| 2708 | + } else { | ||
| 2709 | + imgElem.src = newUri; | ||
| 2710 | + } | ||
| 2711 | + | ||
| 2712 | + var thumbnail = elem.down('.readview-image-thumbnail'); | ||
| 2713 | + if (thumbnail) { | ||
| 2714 | + thumbnail.src = "file:///var/luna/data/extractfs/"+newUri+":0:0:31:31:4"; | ||
| 2715 | + thumbnail.show(); | ||
| 2716 | + } | ||
| 2717 | + } | ||
| 2718 | + this.controller.get('download_icon_' + attachment.id).hide(); // remove the download arrow from the icon | ||
| 2719 | + this.controller.get('progress_' + attachment.id).hide(); // ensures the progress bar is no longer shown | ||
| 2720 | + this.controller.get('file_size_' + attachment.id).show(); // since progress bar is gone, show the file size | ||
| 2721 | + } | ||
| 2722 | + }, | ||
| 2723 | + | ||
| 2724 | + attachmentDownloadProgress: function(info) { | ||
| 2725 | + // If the object doesn't contain a 'id' property, it isn't valid download progress | ||
| 2726 | + if (info.id) { | ||
| 2727 | + if (info.status == Message.ATTACHMENT_LOAD_COMPLETED_EVENT) { | ||
| 2728 | + Mojo.Log.info("attachmentDownloadProgress complete for id:", info.id); | ||
| 2729 | + this.attachmentDLProgress.clearSubscription(info.id); | ||
| 2730 | + this.attachmentUpdateProgressbar(info.id, 100); | ||
| 2731 | + | ||
| 2732 | + // Final step to fully download is to get details of this attachment, including the URI. | ||
| 2733 | + Message.getAttachmentDetails(this.controller, info.id, this.handleAttachmentDetails.bind(this), this.attachmentError.bind(this, info.id)); | ||
| 2734 | + } | ||
| 2735 | + else if (info.status == Message.ATTACHMENT_LOAD_PROGRESS_EVENT) { | ||
| 2736 | + // The transports can be rather aggressive about sending progress notifications so | ||
| 2737 | + // defend against that by only updating the UI periodically | ||
| 2738 | + var now = new Date().getTime(); | ||
| 2739 | + if (now < this.attachmentDLProgress.lastUpdate + 200) { | ||
| 2740 | + this.attachmentDLProgress.progress[info.id] = info.progress; | ||
| 2741 | + } else { | ||
| 2742 | + this.attachmentDLProgress.lastUpdate = now; | ||
| 2743 | + var that = this; | ||
| 2744 | + if (info.progress !== undefined) { | ||
| 2745 | + this.attachmentDLProgress.progress[info.id] = info.progress; | ||
| 2746 | + } | ||
| 2747 | + var progressObj = this.attachmentDLProgress.progress; | ||
| 2748 | + Object.keys(progressObj).each(function(id) { | ||
| 2749 | + var progress = progressObj[id]; | ||
| 2750 | + Mojo.Log.info("attachmentDownloadProgress id: ", id, ", progress: ", progress); | ||
| 2751 | + that.attachmentUpdateProgressbar(id, progress); | ||
| 2752 | + }); | ||
| 2753 | + } | ||
| 2754 | + } | ||
| 2755 | + } | ||
| 2756 | + }, | ||
| 2757 | + | ||
| 2758 | + attachmentUpdateProgressbar: function(id, percent) { | ||
| 2759 | + var progressGroup = this.controller.get('progress_' + id); | ||
| 2760 | + if (progressGroup) { | ||
| 2761 | + var totalWidth = 2.48; // = 248 / 100% | ||
| 2762 | + var progressWidth = Math.round(totalWidth * percent); | ||
| 2763 | + progressGroup.down(0).setStyle({width:progressWidth+"px"}); | ||
| 2764 | + var backgrndWidth = Math.round(totalWidth * (100 - percent)); | ||
| 2765 | + progressGroup.down(1).setStyle({width:backgrndWidth+"px"}); | ||
| 2766 | + } else { | ||
| 2767 | + Mojo.Log.error("Attachment ID ", id, " is invalid."); | ||
| 2768 | + } | ||
| 2769 | + }, | ||
| 2770 | + | ||
| 2771 | + hideAttachmentList: function(event) { | ||
| 2772 | + if (this.attachmentListShown) { | ||
| 2773 | + var targetRow = this.controller.get(event.target); | ||
| 2774 | + if (!targetRow.hasClassName('email-readview-attachments')) { | ||
| 2775 | + targetRow = targetRow.up('div.email-readview-attachments'); | ||
| 2776 | + } | ||
| 2777 | + | ||
| 2778 | + // Only hide the attachments list if the mousedown target was outside the | ||
| 2779 | + // list elements. Otherwise, reset the hide timer | ||
| 2780 | + if (targetRow == null) { | ||
| 2781 | + this.showHideAttachmentList(); | ||
| 2782 | + } else if (this.hideTimeout) { | ||
| 2783 | + clearTimeout(this.hideTimeout); | ||
| 2784 | + this.hideTimeout = setTimeout(this.showHideAttachmentList.bind(this), 15000); | ||
| 2785 | + } | ||
| 2786 | + } | ||
| 2787 | + }, | ||
| 2788 | + | ||
| 2789 | + showHideAttachmentList: function() { | ||
| 2790 | + if (this.hideTimeout) { | ||
| 2791 | + clearTimeout(this.hideTimeout); | ||
| 2792 | + this.hideTimeout = null; | ||
| 2793 | + } | ||
| 2794 | + | ||
| 2795 | + if (!this.attachmentListShown) { | ||
| 2796 | + this.attachmentList.show(); | ||
| 2797 | + this.attachmentsShowElem.hide(); | ||
| 2798 | + } | ||
| 2799 | + | ||
| 2800 | + var options = {reverse:this.attachmentListShown, | ||
| 2801 | + onComplete: this.animationComplete.bind(this), | ||
| 2802 | + curve: 'over-easy', | ||
| 2803 | + from: 46, | ||
| 2804 | + to: this.attachmentListHeight, | ||
| 2805 | + duration: 0.6}; | ||
| 2806 | + Mojo.Animation.animateStyle(this.attachmentList, 'height', 'bezier', options); | ||
| 2807 | + }, | ||
| 2808 | + | ||
| 2809 | + animationComplete: function(listElem, cancelled) { | ||
| 2810 | + if (!cancelled) { | ||
| 2811 | + this.attachmentListShown = !this.attachmentListShown; | ||
| 2812 | + if (this.attachmentListShown) { | ||
| 2813 | + this.attachmentsShowElem.hide(); | ||
| 2814 | + this.attachmentList.show(); | ||
| 2815 | + | ||
| 2816 | + this.hideTimeout = setTimeout(this.showHideAttachmentList.bind(this), 15000); | ||
| 2817 | + } else { | ||
| 2818 | + this.attachmentList.hide(); | ||
| 2819 | + this.attachmentsShowElem.show(); | ||
| 2820 | + } | ||
| 2821 | + } | ||
| 2822 | + }, | ||
| 2823 | + | ||
| 2824 | + /** | ||
| 2825 | + * User clicked on a hyperlink. | ||
| 2826 | + */ | ||
| 2827 | + handleLinkClicked: function(event) { | ||
| 2828 | + Mojo.Log.info("handleLinkClicked %s", event.url); | ||
| 2829 | + this.controller.serviceRequest('palm://com.palm.applicationManager', | ||
| 2830 | + { | ||
| 2831 | + method: 'open', | ||
| 2832 | + parameters: {target: event.url} | ||
| 2833 | + }); | ||
| 2834 | + }, | ||
| 2835 | + | ||
| 2836 | + /** | ||
| 2837 | + * WebView widget wants us to create a new page. | ||
| 2838 | + */ | ||
| 2839 | + handleCreatePage: function(event) { | ||
| 2840 | + Mojo.Log.info("handleCreatePage: %s", event.pageIdentifier); | ||
| 2841 | + this.controller.serviceRequest('palm://com.palm.applicationManager', | ||
| 2842 | + { | ||
| 2843 | + method: 'open', | ||
| 2844 | + parameters: { | ||
| 2845 | + 'id': 'com.palm.app.browser', | ||
| 2846 | + 'params': {scene: 'page', pageIdentifier: event.pageIdentifier} | ||
| 2847 | + } | ||
| 2848 | + }); | ||
| 2849 | + }, | ||
| 2850 | + | ||
| 2851 | + /** | ||
| 2852 | + * handle a menu command. | ||
| 2853 | + */ | ||
| 2854 | + handleCommand: function(event) { | ||
| 2855 | + if (event.type == Mojo.Event.command) { | ||
| 2856 | + try { | ||
| 2857 | + switch (event.command) { | ||
| 2858 | + case 'reply': | ||
| 2859 | + this.reply(); | ||
| 2860 | + break; | ||
| 2861 | + | ||
| 2862 | + case 'replyAll': | ||
| 2863 | + this.replyAll(); | ||
| 2864 | + break; | ||
| 2865 | + | ||
| 2866 | + case 'forward': | ||
| 2867 | + this.forward(); | ||
| 2868 | + break; | ||
| 2869 | + | ||
| 2870 | + case 'delete': | ||
| 2871 | + this.deleteEmail(); | ||
| 2872 | + break; | ||
| 2873 | + | ||
| 2874 | + case 'move': | ||
| 2875 | + this.controller.stageController.pushScene("moveto", this.account); | ||
| 2876 | + break; | ||
| 2877 | + | ||
| 2878 | + case 'mark-unread': | ||
| 2879 | + var currentLabel = this.markUnreadMenuItem.label; | ||
| 2880 | + var markRead = (currentLabel == MessageAssistant.kAppMenuMarkRead); | ||
| 2881 | + Email.setRead(this.data.id, markRead); | ||
| 2882 | + if (markRead) { | ||
| 2883 | + this.markUnreadMenuItem.label = MessageAssistant.kAppMenuMarkUnread; | ||
| 2884 | + } else { | ||
| 2885 | + this.markUnreadMenuItem.label = MessageAssistant.kAppMenuMarkRead; | ||
| 2886 | + } | ||
| 2887 | + break; | ||
| 2888 | + | ||
| 2889 | + case 'flag': | ||
| 2890 | + this.handleToggleFavorites(); | ||
| 2891 | + break; | ||
| 2892 | + | ||
| 2893 | + case Mojo.Menu.prefsCmd: | ||
| 2894 | + MenuController.showPrefs(this.controller.stageController); | ||
| 2895 | + break; | ||
| 2896 | + | ||
| 2897 | + case Mojo.Menu.helpCmd: | ||
| 2898 | + MenuController.showHelp(); | ||
| 2899 | + break; | ||
| 2900 | + } | ||
| 2901 | + } | ||
| 2902 | + catch (e) { | ||
| 2903 | + Mojo.Log.error("MessageAssistant.handleCommand: "+ e.message +" in "+ e.sourceURL +"("+ e.line +")" ); | ||
| 2904 | + } | ||
| 2905 | + } | ||
| 2906 | + // Enable prefs & help menu items | ||
| 2907 | + else if (event.type == Mojo.Event.commandEnable && | ||
| 2908 | + (event.command == Mojo.Menu.prefsCmd || event.command == Mojo.Menu.helpCmd)) { | ||
| 2909 | + event.stopPropagation(); | ||
| 2910 | + } | ||
| 2911 | + }, | ||
| 2912 | + | ||
| 2913 | + handleInlineImageSaved: function(event) { | ||
| 2914 | + if (event.status) { | ||
| 2915 | + var filepath = this.makeTitleFromUrl(event.filepath); | ||
| 2916 | + var message = $L('Saving "#{path}"').interpolate({path: filepath}); | ||
| 2917 | + Mojo.Controller.appController.showBanner( | ||
| 2918 | + {messageText: message}, | ||
| 2919 | + {banner: 'image', filename: event.filepath}); | ||
| 2920 | + } | ||
| 2921 | + }, | ||
| 2922 | + | ||
| 2923 | + makeTitleFromUrl: function(url) { | ||
| 2924 | + if (url) { | ||
| 2925 | + var result = url.match(/^.*\/([^\/]+)$/); | ||
| 2926 | + if ((result !== null) && (result.length > 1)) { | ||
| 2927 | + return result[1]; | ||
| 2928 | + } | ||
| 2929 | + } | ||
| 2930 | + | ||
| 2931 | + return url; | ||
| 2932 | + }, | ||
| 2933 | + | ||
| 2934 | + handleWebViewSingleTap: function(event) { | ||
| 2935 | + try { | ||
| 2936 | + var tapPt = Element.viewportOffset(this.webview); | ||
| 2937 | + tapPt.left = event.centerX - tapPt.left; | ||
| 2938 | + tapPt.top = event.centerY - tapPt.top; | ||
| 2939 | + | ||
| 2940 | + //Mojo.Log.info("MessageAssistant.handleWebViewSingleTap(): event.altKey=%s, tapPt.left=%d, tapPt.top=%d", event.altKey, tapPt.left, tapPt.top); | ||
| 2941 | + if (event.altKey) { | ||
| 2942 | + var popupItems = [ | ||
| 2943 | + {label: $L('Open URL'), command:'openNew'}, | ||
| 2944 | + {label: $L('Share Link'), command:'shareUrl'}, | ||
| 2945 | + {label: $L('Copy URL'), command:'copyUrl'}, | ||
| 2946 | + {label: $L('Copy to Photos'), command:'copyToPhotos'}, | ||
| 2947 | + {label: $L('Share Image'), command:'shareImage'} //, | ||
| 2948 | + //{label: $L('Set Wallpaper'), command:'setWallpaper'} | ||
| 2949 | + ]; | ||
| 2950 | + | ||
| 2951 | + var findItem = function(command) { | ||
| 2952 | + var i; | ||
| 2953 | + for (i = 0; i < popupItems.length; i++) { | ||
| 2954 | + if (popupItems[i].command === command) { | ||
| 2955 | + return popupItems[i]; | ||
| 2956 | + } | ||
| 2957 | + } | ||
| 2958 | + }; | ||
| 2959 | + | ||
| 2960 | + var selectedCommand; | ||
| 2961 | + var imageInfo; | ||
| 2962 | + | ||
| 2963 | + var saveImageCallback = function(succeeded, path) { | ||
| 2964 | + if (succeeded) { | ||
| 2965 | + switch (selectedCommand) { | ||
| 2966 | + case 'shareImage': | ||
| 2967 | + this.shareImage(imageInfo, path); | ||
| 2968 | + break; | ||
| 2969 | + case 'setWallpaper': | ||
| 2970 | + this.setWallpaper(path); | ||
| 2971 | + break; | ||
| 2972 | + case 'copyToPhotos': | ||
| 2973 | + this.showOkAlert($L('Image Saved'), | ||
| 2974 | + $L('The image was successfully added to your photo album.')); | ||
| 2975 | + break; | ||
| 2976 | + } | ||
| 2977 | + } | ||
| 2978 | + else { | ||
| 2979 | + this.showOkAlert($L('Error Saving Image'), | ||
| 2980 | + $L('There was an error saving the selected image.')); | ||
| 2981 | + } | ||
| 2982 | + }.bind(this); | ||
| 2983 | + | ||
| 2984 | + var urlInfo = {}; | ||
| 2985 | + var popupSelectFunc = function(value) { | ||
| 2986 | + selectedCommand = value; | ||
| 2987 | + | ||
| 2988 | + switch (value) { | ||
| 2989 | + case 'openNew': | ||
| 2990 | + this.newBrowserPage(urlInfo.url); | ||
| 2991 | + break; | ||
| 2992 | + case 'shareUrl': | ||
| 2993 | + this.shareUrl(urlInfo.url, urlInfo.desc); | ||
| 2994 | + break; | ||
| 2995 | + case 'copyUrl': | ||
| 2996 | + this.controller.stageController.setClipboard(urlInfo.url); | ||
| 2997 | + break; | ||
| 2998 | + case 'copyToPhotos': | ||
| 2999 | + this.webview.mojo.saveImageAtPoint(tapPt.left, tapPt.top, "/media/internal", saveImageCallback); | ||
| 3000 | + break; | ||
| 3001 | + case 'shareImage': | ||
| 3002 | + this.webview.mojo.saveImageAtPoint(tapPt.left, tapPt.top, "/tmp", saveImageCallback); | ||
| 3003 | + break; | ||
| 3004 | + case 'setWallpaper': | ||
| 3005 | + this.webview.mojo.saveImageAtPoint(tapPt.left, tapPt.top, "/media/internal", saveImageCallback); | ||
| 3006 | + break; | ||
| 3007 | + } | ||
| 3008 | + }.bind(this); | ||
| 3009 | + | ||
| 3010 | + var imageInfoResponse = function(response) { | ||
| 3011 | + imageInfo = response; | ||
| 3012 | + var usedItems = []; | ||
| 3013 | + | ||
| 3014 | + if (urlInfo.url) { | ||
| 3015 | + usedItems.push( findItem('openNew') ); | ||
| 3016 | + usedItems.push( findItem('shareUrl') ); | ||
| 3017 | + usedItems.push( findItem('copyUrl') ); | ||
| 3018 | + } | ||
| 3019 | + | ||
| 3020 | + if (response.src) { | ||
| 3021 | + usedItems.push( findItem('shareImage') ); | ||
| 3022 | + } | ||
| 3023 | + | ||
| 3024 | + if (this.supportedImageType(response.src, response.mimeType)) { | ||
| 3025 | + usedItems.push( findItem('copyToPhotos') ); | ||
| 3026 | + //usedItems.push( findItem('setWallpaper') ); | ||
| 3027 | + } | ||
| 3028 | + | ||
| 3029 | + if (usedItems.length) { | ||
| 3030 | + this.controller.popupSubmenu({ onChoose: popupSelectFunc, items: usedItems }); | ||
| 3031 | + } | ||
| 3032 | + }.bind(this); | ||
| 3033 | + | ||
| 3034 | + var urlInspectResponse = function(response) { | ||
| 3035 | + urlInfo = response || {}; | ||
| 3036 | + this.webview.mojo.getImageInfoAtPoint(tapPt.left, tapPt.top, imageInfoResponse); | ||
| 3037 | + }.bind(this); | ||
| 3038 | + | ||
| 3039 | + this.webview.mojo.inspectUrlAtPoint(tapPt.left, tapPt.top, urlInspectResponse); | ||
| 3040 | + } | ||
| 3041 | + } | ||
| 3042 | + catch (e) { | ||
| 3043 | + Mojo.Log.logException(e); | ||
| 3044 | + } | ||
| 3045 | + }, | ||
| 3046 | + | ||
| 3047 | + supportedImageType:function(url, mimeType) { | ||
| 3048 | + switch (this.getImageType(url, mimeType)) { | ||
| 3049 | + case 'jpeg': | ||
| 3050 | + case 'png': | ||
| 3051 | + case 'bmp': // We only support 24/32 bit BMP's and don't differentiate here | ||
| 3052 | + // GIF not yet supported | ||
| 3053 | + return true; | ||
| 3054 | + default: | ||
| 3055 | + return false; | ||
| 3056 | + } | ||
| 3057 | + }, | ||
| 3058 | + | ||
| 3059 | + getImageType: function(url, mimeType) { | ||
| 3060 | + url = url || ''; | ||
| 3061 | + mimeType = mimeType || ''; | ||
| 3062 | + var suffix = ''; | ||
| 3063 | + try { | ||
| 3064 | + suffix = this.getResourceExtension(url); | ||
| 3065 | + if (suffix === null) { | ||
| 3066 | + suffix = ''; | ||
| 3067 | + } | ||
| 3068 | + } | ||
| 3069 | + catch (e) { | ||
| 3070 | + Mojo.Log.logException(e); | ||
| 3071 | + } | ||
| 3072 | + | ||
| 3073 | + suffix = suffix.toLowerCase(); | ||
| 3074 | + mimeType = mimeType.toLowerCase(); | ||
| 3075 | + | ||
| 3076 | + if (suffix === 'jpg' || suffix === 'jpeg' || suffix === 'jpe' || mimeType === 'image/jpeg') { | ||
| 3077 | + return 'jpeg'; | ||
| 3078 | + } | ||
| 3079 | + else if (suffix === 'bmp' || mimeType === 'image/bmp') { | ||
| 3080 | + return 'bmp'; | ||
| 3081 | + } | ||
| 3082 | + else if (suffix === 'png' || mimeType === 'image/png') { | ||
| 3083 | + return 'png'; | ||
| 3084 | + } | ||
| 3085 | + else if (suffix === 'gif' || mimeType === 'image/gif') { | ||
| 3086 | + return 'gif'; | ||
| 3087 | + } | ||
| 3088 | + else { | ||
| 3089 | + return 'unknown'; | ||
| 3090 | + } | ||
| 3091 | + }, | ||
| 3092 | + | ||
| 3093 | + getResourceExtension: function(url) { | ||
| 3094 | + var p = new Poly9.URLParser(url); | ||
| 3095 | + | ||
| 3096 | + var matches = p.getPathname().match(/\.([^\.]*)$/i); | ||
| 3097 | + if (matches) { | ||
| 3098 | + return matches[1]; | ||
| 3099 | + } | ||
| 3100 | + else { | ||
| 3101 | + return null; | ||
| 3102 | + } | ||
| 3103 | + }, | ||
| 3104 | + | ||
| 3105 | + newBrowserPage: function(url) { | ||
| 3106 | + this.controller.serviceRequest('palm://com.palm.applicationManager', | ||
| 3107 | + { | ||
| 3108 | + method: 'open', | ||
| 3109 | + parameters: {target: url} | ||
| 3110 | + }); | ||
| 3111 | + }, | ||
| 3112 | + | ||
| 3113 | + shareUrl: function(url, title) { | ||
| 3114 | + if (url === undefined) { | ||
| 3115 | + return; | ||
| 3116 | + } | ||
| 3117 | + | ||
| 3118 | + if (!title) { | ||
| 3119 | + try { | ||
| 3120 | + title = $L("page at #{host}").interpolate({host: UrlUtil.getUrlHost(url)}); | ||
| 3121 | + } | ||
| 3122 | + catch (e) { | ||
| 3123 | + title = url; | ||
| 3124 | + } | ||
| 3125 | + } | ||
| 3126 | + | ||
| 3127 | + var text = $L("Here's a website I think you'll like: <a href='#{src}'>#{title}</a>").interpolate( | ||
| 3128 | + {src: url, title: title}); | ||
| 3129 | + var parameters = { | ||
| 3130 | + summary: $L('Check out this web page...'), | ||
| 3131 | + text: text | ||
| 3132 | + }; | ||
| 3133 | + var email = new Email(); | ||
| 3134 | + email.evalParams(parameters); | ||
| 3135 | + AppAssistant.openComposeStage(email); | ||
| 3136 | + }, | ||
| 3137 | + | ||
| 3138 | + shareImage: function(imageInfoObj, pathToImage) { | ||
| 3139 | + var title; | ||
| 3140 | + if (imageInfoObj.title && imageInfoObj.title.length) { | ||
| 3141 | + title = imageInfoObj.title; | ||
| 3142 | + } | ||
| 3143 | + else if (imageInfoObj.altText && imageInfoObj.altText.length) { | ||
| 3144 | + title = imageInfoObj.altText; | ||
| 3145 | + } | ||
| 3146 | + else { | ||
| 3147 | + var p = new Poly9.URLParser(imageInfoObj.src); | ||
| 3148 | + title = $L('picture link'); | ||
| 3149 | + try { | ||
| 3150 | + if (imageInfoObj.src !== 'data:') { | ||
| 3151 | + title = $L("picture at #{host}").interpolate( | ||
| 3152 | + {host: p.getHost()}); | ||
| 3153 | + } | ||
| 3154 | + } | ||
| 3155 | + catch (e) {} | ||
| 3156 | + } | ||
| 3157 | + | ||
| 3158 | + var text = $L("Here's a picture I think you'll like: <a href='#{src}'>#{title}</a>").interpolate( | ||
| 3159 | + {src: imageInfoObj.src, title: title}); | ||
| 3160 | + | ||
| 3161 | + var parameters = { | ||
| 3162 | + summary: $L('Check out this picture...'), | ||
| 3163 | + text: text, | ||
| 3164 | + attachments: [{fullPath: pathToImage}] | ||
| 3165 | + }; | ||
| 3166 | + var email = new Email(); | ||
| 3167 | + email.evalParams(parameters); | ||
| 3168 | + AppAssistant.openComposeStage(email); | ||
| 3169 | + }, | ||
| 3170 | + | ||
| 3171 | + setWallpaper: function(pathToImage) { | ||
| 3172 | + var errorTitle = $L("Error Setting Wallpaper"); | ||
| 3173 | + | ||
| 3174 | + var onSetSuccess = function(response) { | ||
| 3175 | + this.showOkAlert($L("Wallpaper has been set"), | ||
| 3176 | + $L("The image has been successfully set as your wallpaper.")); | ||
| 3177 | + }.bind(this); | ||
| 3178 | + | ||
| 3179 | + var onSetFailure = function(response) { | ||
| 3180 | + this.showOkAlert(errorTitle, $L("Cannot set picture as current wallpaper.")); | ||
| 3181 | + }.bind(this); | ||
| 3182 | + | ||
| 3183 | + var onImportSuccess = function(response) { | ||
| 3184 | + this.controller.serviceRequest('palm://com.palm.systemservice/', | ||
| 3185 | + { | ||
| 3186 | + method : 'setPreferences', | ||
| 3187 | + parameters: {wallpaper: response.wallpaper}, | ||
| 3188 | + onSuccess: onSetSuccess, | ||
| 3189 | + onFailure: onSetFailure | ||
| 3190 | + }); | ||
| 3191 | + }.bind(this); | ||
| 3192 | + | ||
| 3193 | + var onImportFailure = function() { | ||
| 3194 | + this.showOkAlert(errorTitle, $L("Cannot import picture into wallpaper database.")); | ||
| 3195 | + }.bind(this); | ||
| 3196 | + | ||
| 3197 | + this.controller.serviceRequest('palm://com.palm.systemservice/', { | ||
| 3198 | + method : 'wallpaper/importWallpaper', | ||
| 3199 | + parameters: { | ||
| 3200 | + target: encodeURIComponent(pathToImage), | ||
| 3201 | + scale: "1.0" | ||
| 3202 | + }, | ||
| 3203 | + onSuccess: onImportSuccess, | ||
| 3204 | + onFailure: onImportFailure | ||
| 3205 | + }); | ||
| 3206 | + }, | ||
| 3207 | + | ||
| 3208 | + showOkAlert: function(title, message) | ||
| 3209 | + { | ||
| 3210 | + this.controller.showAlertDialog({ | ||
| 3211 | + title: title, message: message, | ||
| 3212 | + choices:[{label:$L('OK'), value:'1', type:'dismiss'}] | ||
| 3213 | + }); | ||
| 3214 | + }, | ||
| 3215 | + | ||
| 3216 | + handleNextMessagesResponse: function(response) { | ||
| 3217 | + this.nextMessages = response; | ||
| 3218 | + | ||
| 3219 | + var prevEmail = this.controller.get('previous_email'); | ||
| 3220 | + if (!prevEmail) { | ||
| 3221 | + Mojo.Log.error("previous_email element does not yet exist"); | ||
| 3222 | + } else { | ||
| 3223 | + if (response.newer === undefined || response.newer.end) { | ||
| 3224 | + // hide 'previous_email' because there's no more emails in that direction | ||
| 3225 | + prevEmail.addClassName('disabled'); | ||
| 3226 | + } else { | ||
| 3227 | + prevEmail.removeClassName('disabled'); | ||
| 3228 | + } | ||
| 3229 | + } | ||
| 3230 | + | ||
| 3231 | + var nextEmail = this.controller.get('next_email'); | ||
| 3232 | + if (!nextEmail) { | ||
| 3233 | + Mojo.Log.error("next_email element does not yet exist"); | ||
| 3234 | + } else { | ||
| 3235 | + if (response.older === undefined || response.older.end) { | ||
| 3236 | + // hide 'next_email' because there's no more emails in that direction | ||
| 3237 | + nextEmail.addClassName('disabled'); | ||
| 3238 | + } else { | ||
| 3239 | + nextEmail.removeClassName('disabled'); | ||
| 3240 | + } | ||
| 3241 | + } | ||
| 3242 | + }, | ||
| 3243 | + | ||
| 3244 | + gotoNextEmail: function(direction) { | ||
| 3245 | + if (this.nextMessages !== undefined && this.nextMessages[direction] !== undefined) { | ||
| 3246 | + var details = this.nextMessages[direction]; | ||
| 3247 | + if (!details.end && details.id > 0) { | ||
| 3248 | + if (this.transition !== null) { | ||
| 3249 | + this.transition.cleanup(); | ||
| 3250 | + } | ||
| 3251 | + this.transition = this.controller.prepareTransition(Mojo.Transition.crossFade, false); | ||
| 3252 | + this.prepareForNewMessage(details); | ||
| 3253 | + } | ||
| 3254 | + } | ||
| 3255 | + }, | ||
| 3256 | + | ||
| 3257 | + prepareForNewMessage: function(details) { | ||
| 3258 | + this.data = { id: details.id, senderDetails:{} }; // data.id | ||
| 3259 | + this.account = {}; | ||
| 3260 | + this.gotFirstResponse = false; | ||
| 3261 | + this.bodyLeftOffset = 0; | ||
| 3262 | + // Clear out the old email body by loading a simple empty page | ||
| 3263 | + this.webview.mojo.openURL(Mojo.appPath + "emptypage.html"); | ||
| 3264 | + this.plainTextBody.hide(); | ||
| 3265 | + | ||
| 3266 | + // stop listening to all these | ||
| 3267 | + this.controller.get('previous_email').stopObserving(Mojo.Event.tap, this.boundGotoNextEmailNewer); | ||
| 3268 | + this.controller.get('next_email').stopObserving(Mojo.Event.tap, this.boundGotoNextEmailOlder); | ||
| 3269 | + if (this.recipientController) { | ||
| 3270 | + this.recipientController.up(".palm-row").stopObserving(Mojo.Event.tap, this.boundShowHideRecipients, true); | ||
| 3271 | + } | ||
| 3272 | + var elem; | ||
| 3273 | + elem = this.controller.get('invite-accept'); | ||
| 3274 | + if (elem) { | ||
| 3275 | + elem.stopObserving(Mojo.Event.tap, this.boundHandleInviteResponseAccept); | ||
| 3276 | + } | ||
| 3277 | + elem = this.controller.get('invite-tentative'); | ||
| 3278 | + if (elem) { | ||
| 3279 | + elem.stopObserving(Mojo.Event.tap, this.boundHandleInviteResponseTentative); | ||
| 3280 | + } | ||
| 3281 | + this.controller.get('invite-decline'); | ||
| 3282 | + if (elem) { | ||
| 3283 | + elem.stopObserving(Mojo.Event.tap, this.boundHandleInviteResponseDecline); | ||
| 3284 | + } | ||
| 3285 | + | ||
| 3286 | + // reset the horizontal positioning of these two blocks. | ||
| 3287 | + this.emailHeaderBlock.setStyle({ 'left': '0px' }); | ||
| 3288 | + this.emailPicturesBlock.setStyle({ 'left': '0px' }); | ||
| 3289 | + | ||
| 3290 | + // Subscribe to the new message | ||
| 3291 | + if (this.waitingForMessageBodyTimeout !== undefined) { | ||
| 3292 | + clearTimeout(this.waitingForMessageBodyTimeout); | ||
| 3293 | + this.waitingForMessageBodyTimeout = undefined; | ||
| 3294 | + } | ||
| 3295 | + if (this.messageSubscription) { | ||
| 3296 | + this.messageSubscription.cancel(); | ||
| 3297 | + } | ||
| 3298 | + this.messageSubscription = new Mojo.Service.Request(Message.identifier, { | ||
| 3299 | + method: 'messageDetail', | ||
| 3300 | + parameters: { 'message':this.data.id, subscribe:true }, | ||
| 3301 | + onSuccess: this.messageDetailsUpdated.bind(this), | ||
| 3302 | + onFailure: this.waitMessageError.bind(this) | ||
| 3303 | + }); | ||
| 3304 | + | ||
| 3305 | + Message.getFolderAndAccount(this.controller, this.data.id, this.folderAndAccountDetails.bind(this)); | ||
| 3306 | + }, | ||
| 3307 | + | ||
| 3308 | + /** | ||
| 3309 | + * Called by the webview widget when setup is complete? | ||
| 3310 | + */ | ||
| 3311 | + ready: function() { | ||
| 3312 | + this.webview.mojo.addUrlRedirect("^file:.*", false, "", 0); | ||
| 3313 | + this.webview.mojo.addUrlRedirect(".*", true, "", 0); | ||
| 3314 | + }, | ||
| 3315 | + | ||
| 3316 | + setupMessage: function() { | ||
| 3317 | + // Setup the WebView for the body text | ||
| 3318 | + // TODO autowidth to true? | ||
| 3319 | + var emailStageController = Mojo.Controller.appController.getStageController("email"); | ||
| 3320 | + var attr = {minFontSize:18, | ||
| 3321 | + cacheAdapter:true, | ||
| 3322 | + fitWidth: false, | ||
| 3323 | + virtualpagewidth: emailStageController.window.innerWidth, | ||
| 3324 | + minimumpageheight: 32, // Start out very short in case the message body empty | ||
| 3325 | + showClickedLink:true}; | ||
| 3326 | + this.controller.setupWidget('email_body_text', attr); | ||
| 3327 | + this.controller.setupWidget('email_no_body_spinner', { spinnerSize: Mojo.Widget.spinnerSmall }); | ||
| 3328 | + | ||
| 3329 | + this.webview = this.controller.get('email_body_text'); | ||
| 3330 | + this.webview.addEventListener(Mojo.Event.webViewUrlRedirect, this.boundHandleLinkClicked, false); | ||
| 3331 | + this.webview.addEventListener(Mojo.Event.webViewMimeNotSupported, this.boundHandleLinkClicked, false); | ||
| 3332 | + this.webview.addEventListener(Mojo.Event.webViewMimeHandoff, this.boundHandleLinkClicked, false); | ||
| 3333 | + this.webview.addEventListener(Mojo.Event.webViewImageSaved, this.boundHandleInlineImageSaved, false); | ||
| 3334 | + this.webview.addEventListener('singletap', this.boundHandleWebViewSingleTap, true); | ||
| 3335 | + | ||
| 3336 | + this.waitingForMessageBody = undefined; | ||
| 3337 | + // subscribe to the message details because the transport may need to send updates in the case where the | ||
| 3338 | + // email body and/or attachments isn't yet downloaded | ||
| 3339 | + this.messageSubscription = new Mojo.Service.Request(Message.identifier, { | ||
| 3340 | + method: 'messageDetail', | ||
| 3341 | + parameters: { 'message':this.data.id, subscribe:true }, | ||
| 3342 | + onSuccess: this.messageDetailsUpdated.bind(this), | ||
| 3343 | + onFailure: this.waitMessageError.bind(this) | ||
| 3344 | + }); | ||
| 3345 | + }, | ||
| 3346 | + | ||
| 3347 | + orientationChanged: function(orientation) { | ||
| 3348 | + if (orientation === "left" || orientation === "right") { | ||
| 3349 | + this.controller.sceneElement.addClassName('landscape'); | ||
| 3350 | + } else { | ||
| 3351 | + this.controller.sceneElement.removeClassName('landscape'); | ||
| 3352 | + } | ||
| 3353 | + }, | ||
| 3354 | + | ||
| 3355 | + focusEmailStage: function() { | ||
| 3356 | + if (this.focusStageTimer) { | ||
| 3357 | + this.focusStageTimer = undefined; | ||
| 3358 | + AppAssistant.focusEmailStage(); | ||
| 3359 | + } | ||
| 3360 | + }, | ||
| 3361 | + | ||
| 3362 | + // This is called from accountpreference assistant when the user removes the account | ||
| 3363 | + accountDeletedNotification: function(accountId) { | ||
| 3364 | + if (accountId === this.account.account) { | ||
| 3365 | + Mojo.Log.warn("MessageAssistant is showing a deleted account, setting up for cleanup"); | ||
| 3366 | + this.popOnActivate = true; | ||
| 3367 | + } | ||
| 3368 | + }, | ||
| 3369 | + | ||
| 3370 | + setup: function() { | ||
| 3371 | + this.delayActivate = true; | ||
| 3372 | + this.messageTarget = this.controller.get('readview-main'); | ||
| 3373 | + this.messageTarget.observe('mousedown', this.hideAttachmentList.bind(this), true); | ||
| 3374 | + this.setupMessage(); | ||
| 3375 | + | ||
| 3376 | + this.emailHeaderBlock = this.controller.get('email_header_block'); | ||
| 3377 | + this.plainTextBody = this.controller.get('email_text'); | ||
| 3378 | + this.emailPicturesBlock = this.controller.get('email_pictures_list'); | ||
| 3379 | + | ||
| 3380 | + this.controller.get('email-readview-attachments-list').observe(Mojo.Event.tap, this.handleAttachmentTapped.bind(this)); | ||
| 3381 | + this.attachmentsShowElem = this.controller.get('show-hide-multi-attachments'); | ||
| 3382 | + this.attachmentsShowElem.observe(Mojo.Event.tap, this.showHideAttachmentList.bind(this)); | ||
| 3383 | + | ||
| 3384 | + this.cmdMenuModel = { | ||
| 3385 | + visible:true, | ||
| 3386 | + items: [ | ||
| 3387 | + {label:$L('Reply'), icon:'reply', command:'reply'}, | ||
| 3388 | + {label:$L('Reply all'), icon:'reply-all', command:'replyAll'}, | ||
| 3389 | + {label:$L('Forward'), icon:'forward-email', command:'forward'}, | ||
| 3390 | + {label:$L('Delete'), icon:'delete', command:'delete'} | ||
| 3391 | + ]}; | ||
| 3392 | + this.controller.setupWidget(Mojo.Menu.commandMenu, undefined, this.cmdMenuModel); | ||
| 3393 | + | ||
| 3394 | + this.markUnreadMenuItem = {label:MessageAssistant.kAppMenuMarkUnread, command:'mark-unread'}; | ||
| 3395 | + this.markSetFlagMenuItem = {label:MessageAssistant.kAppMenuSetFlag, command:'flag'}; | ||
| 3396 | + this.appMenuModel = { | ||
| 3397 | + visible:true, | ||
| 3398 | + items: [ | ||
| 3399 | + this.markUnreadMenuItem, | ||
| 3400 | + this.markSetFlagMenuItem, | ||
| 3401 | + {label:$L('Move to folder...'), command:'move'} | ||
| 3402 | + ]}; | ||
| 3403 | + this.controller.setupWidget(Mojo.Menu.appMenu, undefined, this.appMenuModel); | ||
| 3404 | + | ||
| 3405 | + Message.getFolderAndAccount(this.controller, this.data.id, this.folderAndAccountDetails.bind(this)); | ||
| 3406 | + | ||
| 3407 | + this.recipsDrawer = { openProperty: false }; | ||
| 3408 | + this.controller.setupWidget('email_recipients_drawer', {unstyled:true, modelProperty:'openProperty'}, this.recipsDrawer); | ||
| 3409 | + this.recipsDrawer.element = this.controller.get('email_recipients_drawer'); | ||
| 3410 | + | ||
| 3411 | + this.emailPicturesBlock.observe(Mojo.Event.tap, this.handleImageTapped.bind(this)); | ||
| 3412 | + // stop gesture events on pictures so they don't go to the webview widget | ||
| 3413 | + this.emailPicturesBlock.observe('gesturestart', function(event) { event.stop(); }, false); | ||
| 3414 | + this.emailPicturesBlock.observe('gesturechange', function(event) { event.stop(); }, false); | ||
| 3415 | + this.emailPicturesBlock.observe('gestureend', function(event) { event.stop(); }, false); | ||
| 3416 | + | ||
| 3417 | + this.controller.get('email_from').observe(Mojo.Event.tap, this.handleSenderTap.bind(this)); | ||
| 3418 | + this.controller.get('email_recipients').observe(Mojo.Event.tap, this.handleRecipientListSelect.bind(this)); | ||
| 3419 | + | ||
| 3420 | + this.boundUpdateRecipientStatus = this.updateRecipientStatus.bind(this); | ||
| 3421 | + Mojo.Event.listen(this.controller.stageController.document, Mojo.Event.activate, this.boundUpdateRecipientStatus); | ||
| 3422 | + | ||
| 3423 | + Mojo.Event.listen(this.controller.getSceneScroller(), Mojo.Event.scrollStarting, this.addAsScrollListener.bind(this)); | ||
| 3424 | + }, | ||
| 3425 | + | ||
| 3426 | + cleanup: function() { | ||
| 3427 | + if (this.waitingForMessageBodyTimeout !== undefined) { | ||
| 3428 | + clearTimeout(this.waitingForMessageBodyTimeout); | ||
| 3429 | + this.waitingForMessageBodyTimeout = undefined; | ||
| 3430 | + } | ||
| 3431 | + | ||
| 3432 | + if (this.focusStageTimer !== undefined) { | ||
| 3433 | + clearTimeout(this.focusStageTimer); | ||
| 3434 | + } | ||
| 3435 | + | ||
| 3436 | + this.webview.removeEventListener(Mojo.Event.webViewUrlRedirect, this.boundHandleLinkClicked, false); | ||
| 3437 | + this.webview.removeEventListener(Mojo.Event.webViewMimeNotSupported, this.boundHandleLinkClicked, false); | ||
| 3438 | + this.webview.removeEventListener(Mojo.Event.webViewMimeHandoff, this.boundHandleLinkClicked, false); | ||
| 3439 | + this.webview.removeEventListener(Mojo.Event.webViewImageSaved, this.boundHandleInlineImageSaved, false); | ||
| 3440 | + this.webview.removeEventListener('singletap', this.boundHandleWebViewSingleTap, true); | ||
| 3441 | + | ||
| 3442 | + if (this.messageSubscription) { | ||
| 3443 | + this.messageSubscription.cancel(); | ||
| 3444 | + } | ||
| 3445 | + Mojo.Event.stopListening(this.controller.stageController.document, Mojo.Event.activate, this.boundUpdateRecipientStatus); | ||
| 3446 | + Message.closeMessage(this.controller, this.data.id); | ||
| 3447 | + }, | ||
| 3448 | + | ||
| 3449 | + aboutToActivate: function(callback) { | ||
| 3450 | + if (this.delayActivate === true) { | ||
| 3451 | + this.readyToActivateCallback = callback; | ||
| 3452 | + } else { | ||
| 3453 | + callback(); | ||
| 3454 | + } | ||
| 3455 | + }, | ||
| 3456 | + | ||
| 3457 | + activate: function() { | ||
| 3458 | + // If the scene is invalid (usually because the underlying account was deleted), | ||
| 3459 | + // just pop the scene and no more. | ||
| 3460 | + if (this.popOnActivate === true) { | ||
| 3461 | + this.controller.stageController.popScene(); | ||
| 3462 | + return; | ||
| 3463 | + } | ||
| 3464 | + | ||
| 3465 | + // save the current scene controller physics parameters | ||
| 3466 | + var scroller = this.controller.getSceneScroller(); | ||
| 3467 | + this.savedFlickSpeed = scroller.mojo.kFlickSpeed; | ||
| 3468 | + this.savedFlickRatio = scroller.mojo.kFlickRatio; | ||
| 3469 | + scroller.mojo.updatePhysicsParameters({flickSpeed: 0.12, flickRatio: 0.2}); | ||
| 3470 | + | ||
| 3471 | + // If the scene is ready to activate and it needs to be focused, do that now. | ||
| 3472 | + if (this.focusStageTimer !== undefined) { | ||
| 3473 | + clearTimeout(this.focusStageTimer); | ||
| 3474 | + this.focusEmailStage(); | ||
| 3475 | + } | ||
| 3476 | + | ||
| 3477 | + // prerenderData is only set if the data was supplied from the list assistant. If the | ||
| 3478 | + // service already send a response, it will not include the prerenderData property. | ||
| 3479 | + if (this.data.prerenderData === true) { | ||
| 3480 | + this.prerenderMessage(this.data); | ||
| 3481 | + } | ||
| 3482 | + }, | ||
| 3483 | + | ||
| 3484 | + deactivate: function() { | ||
| 3485 | + // restore the current scene controller physics parameters | ||
| 3486 | + var scroller = this.controller.getSceneScroller(); | ||
| 3487 | + scroller.mojo.updatePhysicsParameters({flickSpeed: this.savedFlickSpeed, flickRatio: this.savedFlickRatio}); | ||
| 3488 | + }, | ||
| 3489 | + | ||
| 3490 | + reply: function() { | ||
| 27 | |||
| 28 | // Very first thing to do with recipients is fix them up for the address picker. | ||
| 29 | EmailRecipient.addAddressPickerFields(resp.recipients); | ||
| 30 | @@ -1710,24 +1717,32 @@ var MessageAssistant = Class.create({ | ||
| 31 | }, | ||
| 32 | |||
| 33 | reply: function() { | ||
| 3491 | 34 | + Email.setRead(this.data.id, true); | |
| 3492 | 35 | + | |
| 3493 | + var email = new Email(); | ||
| 3494 | + email.createReply(this.data, this.account.login); | ||
| 3495 | + MenuController.showComposeView(email); | ||
| 3496 | + }, | ||
| 3497 | + | ||
| 3498 | + replyAll: function() { | ||
| 36 | var email = new Email(); | ||
| 37 | email.createReply(this.data, this.account.login); | ||
| 38 | MenuController.showComposeView(email); | ||
| 39 | }, | ||
| 40 | |||
| 41 | replyAll: function() { | ||
| 3499 | 42 | + Email.setRead(this.data.id, true); | |
| 3500 | 43 | + | |
| 3501 | + var email = new Email(); | ||
| 3502 | + email.createReplyAll(this.data, this.account.login); | ||
| 3503 | + MenuController.showComposeView(email); | ||
| 3504 | + }, | ||
| 3505 | + | ||
| 3506 | + forward: function() { | ||
| 44 | var email = new Email(); | ||
| 45 | email.createReplyAll(this.data, this.account.login); | ||
| 46 | MenuController.showComposeView(email); | ||
| 47 | }, | ||
| 48 | |||
| 49 | forward: function() { | ||
| 3507 | 50 | + Email.setRead(this.data.id, true); | |
| 3508 | 51 | + | |
| 3509 | + var email = new Email(); | ||
| 3510 | + email.createForward(this.data, this.account.login); | ||
| 3511 | + MenuController.showComposeView(email); | ||
| 3512 | + }, | ||
| 3513 | + | ||
| 3514 | + deleteEmail: function() { | ||
| 52 | var email = new Email(); | ||
| 53 | email.createForward(this.data, this.account.login); | ||
| 54 | MenuController.showComposeView(email); | ||
| 55 | }, | ||
| 56 | |||
| 57 | deleteEmail: function() { | ||
| 3515 | 58 | + Email.setRead(this.data.id, true); | |
| 3516 | 59 | + | |
| 3517 | + Email.setDeleted(this.data.id, true); | ||
| 3518 | + this.controller.stageController.popScene(); | ||
| 3519 | + } | ||
| 3520 | +}); | ||
| 3521 | + | ||
| 3522 | +MessageAssistant.kAppMenuMarkRead = $L('Mark as read'); | ||
| 3523 | +MessageAssistant.kAppMenuMarkUnread = $L('Mark as unread'); | ||
| 3524 | +MessageAssistant.kAppMenuSetFlag = $L('Set flag'); | ||
| 3525 | +MessageAssistant.kAppMenuClearFlag = $L('Clear flag'); | ||
| 3526 | + | ||
| 3527 | + | ||
| 60 | Email.setDeleted(this.data.id, true); | ||
| 61 | this.controller.stageController.popScene(); | ||
| 62 | } |

