Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2012 Google Inc. |
| 3 | * Licensed to The Android Open Source Project. |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 18 | var BLOCKED_SRC_ATTR = "blocked-src"; |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 19 | |
Andy Huang | 63b3c67 | 2012-10-05 19:27:28 -0700 | [diff] [blame] | 20 | // the set of Elements currently scheduled for processing in handleAllImageLoads |
| 21 | // this is an Array, but we treat it like a Set and only insert unique items |
| 22 | var gImageLoadElements = []; |
| 23 | |
Andy Huang | 02f9d18 | 2012-11-28 22:38:02 -0800 | [diff] [blame] | 24 | var gScaleInfo; |
| 25 | |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 26 | /** |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 27 | * Only revert transforms that do an imperfect job of shrinking content if they fail |
| 28 | * to shrink by this much. Expressed as a ratio of: |
| 29 | * (original width difference : width difference after transforms); |
| 30 | */ |
Andy Huang | 04e53a2 | 2013-04-21 16:26:33 -0700 | [diff] [blame] | 31 | var TRANSFORM_MINIMUM_EFFECTIVE_RATIO = 0.7; |
| 32 | |
| 33 | // Don't ship with this on. |
| 34 | var DEBUG_DISPLAY_TRANSFORMS = false; |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 35 | |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 36 | var gTransformText = {}; |
| 37 | |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 38 | /** |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 39 | * Returns the page offset of an element. |
| 40 | * |
| 41 | * @param {Element} element The element to return the page offset for. |
| 42 | * @return {left: number, top: number} A tuple including a left and top value representing |
| 43 | * the page offset of the element. |
| 44 | */ |
| 45 | function getTotalOffset(el) { |
| 46 | var result = { |
| 47 | left: 0, |
| 48 | top: 0 |
| 49 | }; |
| 50 | var parent = el; |
| 51 | |
| 52 | while (parent) { |
| 53 | result.left += parent.offsetLeft; |
| 54 | result.top += parent.offsetTop; |
| 55 | parent = parent.offsetParent; |
| 56 | } |
| 57 | |
| 58 | return result; |
| 59 | } |
| 60 | |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 61 | /** |
| 62 | * Walks up the DOM starting at a given element, and returns an element that has the |
| 63 | * specified class name or null. |
| 64 | */ |
| 65 | function up(el, className) { |
| 66 | var parent = el; |
| 67 | while (parent) { |
| 68 | if (parent.classList && parent.classList.contains(className)) { |
| 69 | break; |
| 70 | } |
| 71 | parent = parent.parentNode; |
| 72 | } |
| 73 | return parent || null; |
| 74 | } |
| 75 | |
Andy Huang | 02f9d18 | 2012-11-28 22:38:02 -0800 | [diff] [blame] | 76 | function getCachedValue(div, property, attrName) { |
| 77 | var value; |
| 78 | if (div.hasAttribute(attrName)) { |
| 79 | value = div.getAttribute(attrName); |
| 80 | } else { |
| 81 | value = div[property]; |
| 82 | div.setAttribute(attrName, value); |
| 83 | } |
| 84 | return value; |
| 85 | } |
| 86 | |
Andy Huang | df0d91c | 2012-10-08 18:44:42 -0700 | [diff] [blame] | 87 | function onToggleClick(e) { |
| 88 | toggleQuotedText(e.target); |
| 89 | measurePositions(); |
| 90 | } |
| 91 | |
| 92 | function toggleQuotedText(toggleElement) { |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 93 | var elidedTextElement = toggleElement.nextSibling; |
| 94 | var isHidden = getComputedStyle(elidedTextElement).display == 'none'; |
| 95 | toggleElement.innerHTML = isHidden ? MSG_HIDE_ELIDED : MSG_SHOW_ELIDED; |
| 96 | elidedTextElement.style.display = isHidden ? 'block' : 'none'; |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 97 | |
| 98 | // Revealing the elided text should normalize it to fit-width to prevent |
| 99 | // this message from blowing out the conversation width. |
| 100 | if (isHidden) { |
| 101 | normalizeElementWidths([elidedTextElement]); |
| 102 | } |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 103 | } |
| 104 | |
Andy Huang | 014ea4c | 2012-09-25 14:50:54 -0700 | [diff] [blame] | 105 | function collapseAllQuotedText() { |
Andy Huang | df0d91c | 2012-10-08 18:44:42 -0700 | [diff] [blame] | 106 | processQuotedText(document.documentElement, false /* showElided */); |
Andy Huang | 014ea4c | 2012-09-25 14:50:54 -0700 | [diff] [blame] | 107 | } |
| 108 | |
Andy Huang | df0d91c | 2012-10-08 18:44:42 -0700 | [diff] [blame] | 109 | function processQuotedText(elt, showElided) { |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 110 | var i; |
Andy Huang | 014ea4c | 2012-09-25 14:50:54 -0700 | [diff] [blame] | 111 | var elements = elt.getElementsByClassName("elided-text"); |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 112 | var elidedElement, toggleElement; |
| 113 | for (i = 0; i < elements.length; i++) { |
| 114 | elidedElement = elements[i]; |
| 115 | toggleElement = document.createElement("div"); |
Andy Huang | 82119af | 2012-06-26 17:15:40 -0700 | [diff] [blame] | 116 | toggleElement.className = "mail-elided-text"; |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 117 | toggleElement.innerHTML = MSG_SHOW_ELIDED; |
Andrew Sapperstein | 7c42143 | 2014-03-20 11:06:29 -0700 | [diff] [blame] | 118 | toggleElement.setAttribute("dir", "auto"); |
Andy Huang | df0d91c | 2012-10-08 18:44:42 -0700 | [diff] [blame] | 119 | toggleElement.onclick = onToggleClick; |
| 120 | elidedElement.style.display = 'none'; |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 121 | elidedElement.parentNode.insertBefore(toggleElement, elidedElement); |
Andy Huang | df0d91c | 2012-10-08 18:44:42 -0700 | [diff] [blame] | 122 | if (showElided) { |
| 123 | toggleQuotedText(toggleElement); |
| 124 | } |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 125 | } |
| 126 | } |
| 127 | |
Andy Huang | 4cfe22a | 2012-10-15 18:20:33 -0700 | [diff] [blame] | 128 | function isConversationEmpty(bodyDivs) { |
| 129 | var i, len; |
| 130 | var msgBody; |
| 131 | var text; |
| 132 | |
| 133 | // Check if given divs are empty (in appearance), and disable zoom if so. |
| 134 | for (i = 0, len = bodyDivs.length; i < len; i++) { |
| 135 | msgBody = bodyDivs[i]; |
| 136 | // use 'textContent' to exclude markup when determining whether bodies are empty |
| 137 | // (fall back to more expensive 'innerText' if 'textContent' isn't implemented) |
| 138 | text = msgBody.textContent || msgBody.innerText; |
| 139 | if (text.trim().length > 0) { |
| 140 | return false; |
| 141 | } |
| 142 | } |
| 143 | return true; |
| 144 | } |
| 145 | |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 146 | function normalizeAllMessageWidths() { |
Andy Huang | 4cfe22a | 2012-10-15 18:20:33 -0700 | [diff] [blame] | 147 | var expandedBodyDivs; |
| 148 | var metaViewport; |
| 149 | var contentValues; |
| 150 | var isEmpty; |
| 151 | |
Andy Huang | 4cfe22a | 2012-10-15 18:20:33 -0700 | [diff] [blame] | 152 | expandedBodyDivs = document.querySelectorAll(".expanded > .mail-message-content"); |
| 153 | |
| 154 | isEmpty = isConversationEmpty(expandedBodyDivs); |
| 155 | |
| 156 | normalizeElementWidths(expandedBodyDivs); |
| 157 | |
| 158 | // assemble a working <meta> viewport "content" value from the base value in the |
| 159 | // document, plus any dynamically determined options |
| 160 | metaViewport = document.getElementById("meta-viewport"); |
| 161 | contentValues = [metaViewport.getAttribute("content")]; |
| 162 | if (isEmpty) { |
| 163 | contentValues.push(metaViewport.getAttribute("data-zoom-off")); |
| 164 | } else { |
| 165 | contentValues.push(metaViewport.getAttribute("data-zoom-on")); |
| 166 | } |
| 167 | metaViewport.setAttribute("content", contentValues.join(",")); |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | /* |
| 171 | * Normalizes the width of all elements supplied to the document body's overall width. |
| 172 | * Narrower elements are zoomed in, and wider elements are zoomed out. |
| 173 | * This method is idempotent. |
| 174 | */ |
| 175 | function normalizeElementWidths(elements) { |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 176 | var i; |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 177 | var el; |
Andy Huang | adbf3e8 | 2012-10-13 13:30:19 -0700 | [diff] [blame] | 178 | var documentWidth; |
Andy Huang | 4dc7323 | 2014-02-04 19:58:57 -0800 | [diff] [blame] | 179 | var goalWidth; |
| 180 | var origWidth; |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 181 | var newZoom, oldZoom; |
Andy Huang | 4dc7323 | 2014-02-04 19:58:57 -0800 | [diff] [blame] | 182 | var outerZoom; |
| 183 | var outerDiv; |
Andy Huang | 256b35c | 2012-08-22 15:19:13 -0700 | [diff] [blame] | 184 | |
Andy Huang | adbf3e8 | 2012-10-13 13:30:19 -0700 | [diff] [blame] | 185 | documentWidth = document.body.offsetWidth; |
Andy Huang | 2160d53 | 2014-02-10 15:43:14 -0800 | [diff] [blame] | 186 | goalWidth = WEBVIEW_WIDTH; |
Andy Huang | adbf3e8 | 2012-10-13 13:30:19 -0700 | [diff] [blame] | 187 | |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 188 | for (i = 0; i < elements.length; i++) { |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 189 | el = elements[i]; |
| 190 | oldZoom = el.style.zoom; |
| 191 | // reset any existing normalization |
| 192 | if (oldZoom) { |
| 193 | el.style.zoom = 1; |
| 194 | } |
Andy Huang | 4dc7323 | 2014-02-04 19:58:57 -0800 | [diff] [blame] | 195 | origWidth = el.style.width; |
| 196 | el.style.width = goalWidth + "px"; |
Andy Huang | 4dc7323 | 2014-02-04 19:58:57 -0800 | [diff] [blame] | 197 | transformContent(el, goalWidth, el.scrollWidth); |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 198 | newZoom = documentWidth / el.scrollWidth; |
| 199 | if (NORMALIZE_MESSAGE_WIDTHS) { |
Andy Huang | 4dc7323 | 2014-02-04 19:58:57 -0800 | [diff] [blame] | 200 | if (el.classList.contains("mail-message-content")) { |
| 201 | outerZoom = 1; |
| 202 | } else { |
| 203 | outerDiv = up(el, "mail-message-content"); |
| 204 | outerZoom = outerDiv ? outerDiv.style.zoom : 1; |
| 205 | } |
| 206 | el.style.zoom = newZoom / outerZoom; |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 207 | } |
Andy Huang | 4dc7323 | 2014-02-04 19:58:57 -0800 | [diff] [blame] | 208 | el.style.width = origWidth; |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 209 | } |
| 210 | } |
| 211 | |
Andy Huang | 0180f27 | 2013-03-08 18:33:22 -0800 | [diff] [blame] | 212 | function transformContent(el, docWidth, elWidth) { |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 213 | var nodes; |
| 214 | var i, len; |
Andy Huang | 0180f27 | 2013-03-08 18:33:22 -0800 | [diff] [blame] | 215 | var index; |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 216 | var newWidth = elWidth; |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 217 | var wStr; |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 218 | var touched; |
Andy Huang | 0180f27 | 2013-03-08 18:33:22 -0800 | [diff] [blame] | 219 | // the format of entries in this array is: |
| 220 | // entry := [ undoFunction, undoFunctionThis, undoFunctionParamArray ] |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 221 | var actionLog = []; |
| 222 | var node; |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 223 | var done = false; |
| 224 | var msgId; |
| 225 | var transformText; |
| 226 | var existingText; |
| 227 | var textElement; |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 228 | var start; |
Andy Huang | 0ecc582 | 2013-04-21 19:04:49 -0700 | [diff] [blame] | 229 | var beforeWidth; |
| 230 | var tmpActionLog = []; |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 231 | if (elWidth <= docWidth) { |
| 232 | return; |
| 233 | } |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 234 | |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 235 | start = Date.now(); |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 236 | |
| 237 | if (el.parentElement.classList.contains("mail-message")) { |
| 238 | msgId = el.parentElement.id; |
| 239 | transformText = "[origW=" + elWidth + "/" + docWidth; |
| 240 | } |
| 241 | |
Andy Huang | 33578ea | 2013-03-13 19:11:38 -0700 | [diff] [blame] | 242 | // Try munging all divs or textareas with inline styles where the width |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 243 | // is wider than docWidth, and change it to be a max-width. |
| 244 | touched = false; |
Andy Huang | 33578ea | 2013-03-13 19:11:38 -0700 | [diff] [blame] | 245 | nodes = ENABLE_MUNGE_TABLES ? el.querySelectorAll("div[style], textarea[style]") : []; |
| 246 | touched = transformBlockElements(nodes, docWidth, actionLog); |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 247 | if (touched) { |
| 248 | newWidth = el.scrollWidth; |
| 249 | console.log("ran div-width munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth |
| 250 | + " docW=" + docWidth); |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 251 | if (msgId) { |
| 252 | transformText += " DIV:newW=" + newWidth; |
| 253 | } |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 254 | if (newWidth <= docWidth) { |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 255 | done = true; |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 256 | } |
| 257 | } |
| 258 | |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 259 | if (!done) { |
| 260 | // OK, that wasn't enough. Find images with widths and override their widths. |
| 261 | nodes = ENABLE_MUNGE_IMAGES ? el.querySelectorAll("img") : []; |
| 262 | touched = transformImages(nodes, docWidth, actionLog); |
| 263 | if (touched) { |
| 264 | newWidth = el.scrollWidth; |
| 265 | console.log("ran img munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth |
| 266 | + " docW=" + docWidth); |
| 267 | if (msgId) { |
| 268 | transformText += " IMG:newW=" + newWidth; |
| 269 | } |
| 270 | if (newWidth <= docWidth) { |
| 271 | done = true; |
| 272 | } |
Andy Huang | 0180f27 | 2013-03-08 18:33:22 -0800 | [diff] [blame] | 273 | } |
| 274 | } |
| 275 | |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 276 | if (!done) { |
| 277 | // OK, that wasn't enough. Find tables with widths and override their widths. |
Andy Huang | 543e709 | 2013-04-22 11:44:56 -0700 | [diff] [blame] | 278 | // Also ensure that any use of 'table-layout: fixed' is negated, since using |
| 279 | // that with 'width: auto' causes erratic table width. |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 280 | nodes = ENABLE_MUNGE_TABLES ? el.querySelectorAll("table") : []; |
| 281 | touched = addClassToElements(nodes, shouldMungeTable, "munged", |
| 282 | actionLog); |
| 283 | if (touched) { |
| 284 | newWidth = el.scrollWidth; |
| 285 | console.log("ran table munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth |
| 286 | + " docW=" + docWidth); |
| 287 | if (msgId) { |
| 288 | transformText += " TABLE:newW=" + newWidth; |
| 289 | } |
| 290 | if (newWidth <= docWidth) { |
| 291 | done = true; |
| 292 | } |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 293 | } |
| 294 | } |
| 295 | |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 296 | if (!done) { |
| 297 | // OK, that wasn't enough. Try munging all <td> to override any width and nowrap set. |
Andy Huang | 0ecc582 | 2013-04-21 19:04:49 -0700 | [diff] [blame] | 298 | beforeWidth = newWidth; |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 299 | nodes = ENABLE_MUNGE_TABLES ? el.querySelectorAll("td") : []; |
| 300 | touched = addClassToElements(nodes, null /* mungeAll */, "munged", |
Andy Huang | 0ecc582 | 2013-04-21 19:04:49 -0700 | [diff] [blame] | 301 | tmpActionLog); |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 302 | if (touched) { |
| 303 | newWidth = el.scrollWidth; |
| 304 | console.log("ran td munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth |
| 305 | + " docW=" + docWidth); |
| 306 | if (msgId) { |
| 307 | transformText += " TD:newW=" + newWidth; |
| 308 | } |
| 309 | if (newWidth <= docWidth) { |
| 310 | done = true; |
Andy Huang | 0ecc582 | 2013-04-21 19:04:49 -0700 | [diff] [blame] | 311 | } else if (newWidth == beforeWidth) { |
| 312 | // this transform did not improve things, and it is somewhat risky. |
| 313 | // back it out, since it's the last transform and we gained nothing. |
| 314 | undoActions(tmpActionLog); |
| 315 | } else { |
| 316 | // the transform WAS effective (although not 100%) |
| 317 | // copy the temporary action log entries over as normal |
| 318 | for (i = 0, len = tmpActionLog.length; i < len; i++) { |
| 319 | actionLog.push(tmpActionLog[i]); |
| 320 | } |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 321 | } |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 322 | } |
| 323 | } |
| 324 | |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 325 | // If the transformations shrank the width significantly enough, leave them in place. |
| 326 | // We figure that in those cases, the benefits outweight the risk of rendering artifacts. |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 327 | if (!done && (elWidth - newWidth) / (elWidth - docWidth) > |
| 328 | TRANSFORM_MINIMUM_EFFECTIVE_RATIO) { |
| 329 | console.log("transform(s) deemed effective enough"); |
| 330 | done = true; |
| 331 | } |
| 332 | |
| 333 | if (done) { |
| 334 | if (msgId) { |
| 335 | transformText += "]"; |
| 336 | existingText = gTransformText[msgId]; |
| 337 | if (!existingText) { |
| 338 | transformText = "Message transforms: " + transformText; |
| 339 | } else { |
| 340 | transformText = existingText + " " + transformText; |
| 341 | } |
| 342 | gTransformText[msgId] = transformText; |
| 343 | window.mail.onMessageTransform(msgId, transformText); |
Andy Huang | 04e53a2 | 2013-04-21 16:26:33 -0700 | [diff] [blame] | 344 | if (DEBUG_DISPLAY_TRANSFORMS) { |
| 345 | textElement = el.firstChild; |
| 346 | if (!textElement.classList || !textElement.classList.contains("transform-text")) { |
| 347 | textElement = document.createElement("div"); |
| 348 | textElement.classList.add("transform-text"); |
| 349 | textElement.style.fontSize = "10px"; |
| 350 | textElement.style.color = "#ccc"; |
| 351 | el.insertBefore(textElement, el.firstChild); |
| 352 | } |
| 353 | textElement.innerHTML = transformText + "<br>"; |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 354 | } |
Andy Huang | 05c70c8 | 2013-03-14 15:15:50 -0700 | [diff] [blame] | 355 | } |
| 356 | console.log("munger(s) succeeded, elapsed time=" + (Date.now() - start)); |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 357 | return; |
| 358 | } |
| 359 | |
| 360 | // reverse all changes if the width is STILL not narrow enough |
| 361 | // (except the width->maxWidth change, which is not particularly destructive) |
Andy Huang | 0ecc582 | 2013-04-21 19:04:49 -0700 | [diff] [blame] | 362 | undoActions(actionLog); |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 363 | if (actionLog.length > 0) { |
| 364 | console.log("all mungers failed, changes reversed. elapsed time=" + (Date.now() - start)); |
| 365 | } |
| 366 | } |
| 367 | |
Andy Huang | 0ecc582 | 2013-04-21 19:04:49 -0700 | [diff] [blame] | 368 | function undoActions(actionLog) { |
| 369 | for (i = 0, len = actionLog.length; i < len; i++) { |
| 370 | actionLog[i][0].apply(actionLog[i][1], actionLog[i][2]); |
| 371 | } |
| 372 | } |
| 373 | |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 374 | function addClassToElements(nodes, conditionFn, classToAdd, actionLog) { |
| 375 | var i, len; |
| 376 | var node; |
| 377 | var added = false; |
| 378 | for (i = 0, len = nodes.length; i < len; i++) { |
| 379 | node = nodes[i]; |
| 380 | if (!conditionFn || conditionFn(node)) { |
Andy Huang | 4821bbb | 2013-03-13 18:29:57 -0700 | [diff] [blame] | 381 | if (node.classList.contains(classToAdd)) { |
| 382 | continue; |
| 383 | } |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 384 | node.classList.add(classToAdd); |
| 385 | added = true; |
Andy Huang | 0180f27 | 2013-03-08 18:33:22 -0800 | [diff] [blame] | 386 | actionLog.push([node.classList.remove, node.classList, [classToAdd]]); |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 387 | } |
| 388 | } |
| 389 | return added; |
| 390 | } |
| 391 | |
Andy Huang | 33578ea | 2013-03-13 19:11:38 -0700 | [diff] [blame] | 392 | function transformBlockElements(nodes, docWidth, actionLog) { |
| 393 | var i, len; |
| 394 | var node; |
| 395 | var wStr; |
| 396 | var index; |
| 397 | var touched = false; |
| 398 | |
| 399 | for (i = 0, len = nodes.length; i < len; i++) { |
| 400 | node = nodes[i]; |
| 401 | wStr = node.style.width || node.style.minWidth; |
| 402 | index = wStr ? wStr.indexOf("px") : -1; |
| 403 | if (index >= 0 && wStr.slice(0, index) > docWidth) { |
| 404 | saveStyleProperty(node, "width", actionLog); |
| 405 | saveStyleProperty(node, "minWidth", actionLog); |
| 406 | saveStyleProperty(node, "maxWidth", actionLog); |
| 407 | node.style.width = "100%"; |
| 408 | node.style.minWidth = ""; |
| 409 | node.style.maxWidth = wStr; |
| 410 | touched = true; |
| 411 | } |
| 412 | } |
| 413 | return touched; |
| 414 | } |
| 415 | |
Andy Huang | 0180f27 | 2013-03-08 18:33:22 -0800 | [diff] [blame] | 416 | function transformImages(nodes, docWidth, actionLog) { |
| 417 | var i, len; |
| 418 | var node; |
| 419 | var w, h; |
| 420 | var touched = false; |
| 421 | |
| 422 | for (i = 0, len = nodes.length; i < len; i++) { |
| 423 | node = nodes[i]; |
| 424 | w = node.offsetWidth; |
| 425 | h = node.offsetHeight; |
| 426 | // shrink w/h proportionally if the img is wider than available width |
| 427 | if (w > docWidth) { |
Andy Huang | 33578ea | 2013-03-13 19:11:38 -0700 | [diff] [blame] | 428 | saveStyleProperty(node, "maxWidth", actionLog); |
| 429 | saveStyleProperty(node, "width", actionLog); |
| 430 | saveStyleProperty(node, "height", actionLog); |
Andy Huang | 0180f27 | 2013-03-08 18:33:22 -0800 | [diff] [blame] | 431 | node.style.maxWidth = docWidth + "px"; |
| 432 | node.style.width = "100%"; |
| 433 | node.style.height = "auto"; |
Andy Huang | 0180f27 | 2013-03-08 18:33:22 -0800 | [diff] [blame] | 434 | touched = true; |
| 435 | } |
| 436 | } |
| 437 | return touched; |
| 438 | } |
| 439 | |
Andy Huang | 33578ea | 2013-03-13 19:11:38 -0700 | [diff] [blame] | 440 | function saveStyleProperty(node, property, actionLog) { |
| 441 | var savedName = "data-" + property; |
| 442 | node.setAttribute(savedName, node.style[property]); |
| 443 | actionLog.push([undoSetProperty, node, [property, savedName]]); |
| 444 | } |
| 445 | |
Andy Huang | 0180f27 | 2013-03-08 18:33:22 -0800 | [diff] [blame] | 446 | function undoSetProperty(property, savedProperty) { |
| 447 | this.style[property] = savedProperty ? this.getAttribute(savedProperty) : ""; |
| 448 | } |
| 449 | |
Andy Huang | 3a398b2 | 2013-03-08 13:50:36 -0800 | [diff] [blame] | 450 | function shouldMungeTable(table) { |
| 451 | return table.hasAttribute("width") || table.style.width; |
Andy Huang | 5ea5a83 | 2013-03-07 16:49:09 -0800 | [diff] [blame] | 452 | } |
| 453 | |
Andy Huang | f500db8 | 2012-10-23 16:56:27 -0700 | [diff] [blame] | 454 | function hideAllUnsafeImages() { |
| 455 | hideUnsafeImages(document.getElementsByClassName("mail-message-content")); |
| 456 | } |
| 457 | |
| 458 | function hideUnsafeImages(msgContentDivs) { |
| 459 | var i, msgContentCount; |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 460 | var j, imgCount; |
Andy Huang | f500db8 | 2012-10-23 16:56:27 -0700 | [diff] [blame] | 461 | var msgContentDiv, image; |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 462 | var images; |
| 463 | var showImages; |
Andrew Sapperstein | 8ec43e8 | 2013-12-17 18:27:55 -0800 | [diff] [blame] | 464 | var k = 0; |
| 465 | var urls = new Array(); |
| 466 | var messageIds = new Array(); |
Andy Huang | f500db8 | 2012-10-23 16:56:27 -0700 | [diff] [blame] | 467 | for (i = 0, msgContentCount = msgContentDivs.length; i < msgContentCount; i++) { |
| 468 | msgContentDiv = msgContentDivs[i]; |
| 469 | showImages = msgContentDiv.classList.contains("mail-show-images"); |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 470 | |
Andy Huang | f500db8 | 2012-10-23 16:56:27 -0700 | [diff] [blame] | 471 | images = msgContentDiv.getElementsByTagName("img"); |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 472 | for (j = 0, imgCount = images.length; j < imgCount; j++) { |
| 473 | image = images[j]; |
Andrew Sapperstein | 8ec43e8 | 2013-12-17 18:27:55 -0800 | [diff] [blame] | 474 | var src = rewriteRelativeImageSrc(image); |
| 475 | if (src) { |
| 476 | urls[k] = src; |
| 477 | messageIds[k] = msgContentDiv.parentNode.id; |
| 478 | k++; |
| 479 | } |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 480 | attachImageLoadListener(image); |
| 481 | // TODO: handle inline image attachments for all supported protocols |
| 482 | if (!showImages) { |
| 483 | blockImage(image); |
| 484 | } |
| 485 | } |
| 486 | } |
Andrew Sapperstein | 8ec43e8 | 2013-12-17 18:27:55 -0800 | [diff] [blame] | 487 | |
| 488 | window.mail.onInlineAttachmentsParsed(urls, messageIds); |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 489 | } |
| 490 | |
Paul Westbrook | 41dca18 | 2012-08-07 10:43:42 -0700 | [diff] [blame] | 491 | /** |
Andrew Sapperstein | 8ec43e8 | 2013-12-17 18:27:55 -0800 | [diff] [blame] | 492 | * Changes relative paths to absolute path by pre-pending the account uri. |
Paul Westbrook | 41dca18 | 2012-08-07 10:43:42 -0700 | [diff] [blame] | 493 | * @param {Element} imgElement Image for which the src path will be updated. |
Andrew Sapperstein | 8ec43e8 | 2013-12-17 18:27:55 -0800 | [diff] [blame] | 494 | * @returns the rewritten image src string or null if the imgElement was not rewritten. |
Paul Westbrook | 41dca18 | 2012-08-07 10:43:42 -0700 | [diff] [blame] | 495 | */ |
| 496 | function rewriteRelativeImageSrc(imgElement) { |
| 497 | var src = imgElement.src; |
Paul Westbrook | cebcc64 | 2012-08-08 10:06:04 -0700 | [diff] [blame] | 498 | |
| 499 | // DOC_BASE_URI will always be a unique x-thread:// uri for this particular conversation |
| 500 | if (src.indexOf(DOC_BASE_URI) == 0 && (DOC_BASE_URI != CONVERSATION_BASE_URI)) { |
| 501 | // The conversation specifies a different base uri than the document |
| 502 | src = CONVERSATION_BASE_URI + src.substring(DOC_BASE_URI.length); |
| 503 | imgElement.src = src; |
Andrew Sapperstein | 8ec43e8 | 2013-12-17 18:27:55 -0800 | [diff] [blame] | 504 | return src; |
Paul Westbrook | 41dca18 | 2012-08-07 10:43:42 -0700 | [diff] [blame] | 505 | } |
Andrew Sapperstein | 8ec43e8 | 2013-12-17 18:27:55 -0800 | [diff] [blame] | 506 | |
James Lemieux | e1302c3 | 2014-08-21 15:57:46 -0700 | [diff] [blame] | 507 | // preserve cid urls as is |
| 508 | if (src.substring(0, 4) == "cid:") { |
| 509 | return src; |
| 510 | } |
| 511 | |
Andrew Sapperstein | 8ec43e8 | 2013-12-17 18:27:55 -0800 | [diff] [blame] | 512 | return null; |
Paul Westbrook | 41dca18 | 2012-08-07 10:43:42 -0700 | [diff] [blame] | 513 | }; |
| 514 | |
| 515 | |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 516 | function attachImageLoadListener(imageElement) { |
| 517 | // Reset the src attribute to the empty string because onload will only fire if the src |
| 518 | // attribute is set after the onload listener. |
| 519 | var originalSrc = imageElement.src; |
| 520 | imageElement.src = ''; |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 521 | imageElement.onload = imageOnLoad; |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 522 | imageElement.src = originalSrc; |
| 523 | } |
| 524 | |
Andy Huang | 63b3c67 | 2012-10-05 19:27:28 -0700 | [diff] [blame] | 525 | /** |
| 526 | * Handle an onload event for an <img> tag. |
| 527 | * The image could be within an elided-text block, or at the top level of a message. |
| 528 | * When a new image loads, its new bounds may affect message or elided-text geometry, |
| 529 | * so we need to inspect and adjust the enclosing element's zoom level where necessary. |
| 530 | * |
| 531 | * Because this method can be called really often, and zoom-level adjustment is slow, |
| 532 | * we collect the elements to be processed and do them all later in a single deferred pass. |
| 533 | */ |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 534 | function imageOnLoad(e) { |
| 535 | // normalize the quoted text parent if we're in a quoted text block, or else |
| 536 | // normalize the parent message content element |
| 537 | var parent = up(e.target, "elided-text") || up(e.target, "mail-message-content"); |
Andy Huang | 63b3c67 | 2012-10-05 19:27:28 -0700 | [diff] [blame] | 538 | if (!parent) { |
| 539 | // sanity check. shouldn't really happen. |
| 540 | return; |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 541 | } |
Andy Huang | 63b3c67 | 2012-10-05 19:27:28 -0700 | [diff] [blame] | 542 | |
| 543 | // if there was no previous work, schedule a new deferred job |
| 544 | if (gImageLoadElements.length == 0) { |
| 545 | window.setTimeout(handleAllImageOnLoads, 0); |
| 546 | } |
| 547 | |
| 548 | // enqueue the work if it wasn't already enqueued |
| 549 | if (gImageLoadElements.indexOf(parent) == -1) { |
| 550 | gImageLoadElements.push(parent); |
| 551 | } |
| 552 | } |
| 553 | |
| 554 | // handle all deferred work from image onload events |
| 555 | function handleAllImageOnLoads() { |
| 556 | normalizeElementWidths(gImageLoadElements); |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 557 | measurePositions(); |
Andy Huang | 63b3c67 | 2012-10-05 19:27:28 -0700 | [diff] [blame] | 558 | // clear the queue so the next onload event starts a new job |
| 559 | gImageLoadElements = []; |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 560 | } |
| 561 | |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 562 | function blockImage(imageElement) { |
| 563 | var src = imageElement.src; |
Paul Westbrook | 41dca18 | 2012-08-07 10:43:42 -0700 | [diff] [blame] | 564 | if (src.indexOf("http://") == 0 || src.indexOf("https://") == 0 || |
| 565 | src.indexOf("content://") == 0) { |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 566 | imageElement.setAttribute(BLOCKED_SRC_ATTR, src); |
| 567 | imageElement.src = "data:"; |
| 568 | } |
| 569 | } |
| 570 | |
Andy Huang | 2301470 | 2012-07-09 12:50:36 -0700 | [diff] [blame] | 571 | function setWideViewport() { |
| 572 | var metaViewport = document.getElementById('meta-viewport'); |
| 573 | metaViewport.setAttribute('content', 'width=' + WIDE_VIEWPORT_WIDTH); |
| 574 | } |
| 575 | |
Andy Huang | e964eee | 2012-10-02 19:24:58 -0700 | [diff] [blame] | 576 | function restoreScrollPosition() { |
| 577 | var scrollYPercent = window.mail.getScrollYPercent(); |
| 578 | if (scrollYPercent && document.body.offsetHeight > window.innerHeight) { |
| 579 | document.body.scrollTop = Math.floor(scrollYPercent * document.body.offsetHeight); |
| 580 | } |
| 581 | } |
| 582 | |
Andy Huang | bffc312 | 2012-10-05 21:20:56 -0700 | [diff] [blame] | 583 | function onContentReady(event) { |
Andrew Sapperstein | 575e82b | 2014-04-07 16:44:11 -0700 | [diff] [blame] | 584 | // hack for b/1333356 |
| 585 | if (RUNNING_KITKAT_OR_LATER) { |
| 586 | restoreScrollPosition(); |
| 587 | } |
Andy Huang | bffc312 | 2012-10-05 21:20:56 -0700 | [diff] [blame] | 588 | window.mail.onContentReady(); |
| 589 | } |
| 590 | |
| 591 | function setupContentReady() { |
| 592 | var signalDiv; |
| 593 | |
| 594 | // PAGE READINESS SIGNAL FOR JELLYBEAN AND NEWER |
| 595 | // Notify the app on 'webkitAnimationStart' of a simple dummy element with a simple no-op |
| 596 | // animation that immediately runs on page load. The app uses this as a signal that the |
| 597 | // content is loaded and ready to draw, since WebView delays firing this event until the |
| 598 | // layers are composited and everything is ready to draw. |
| 599 | // |
| 600 | // This code is conditionally enabled on JB+ by setting the ENABLE_CONTENT_READY flag. |
| 601 | if (ENABLE_CONTENT_READY) { |
| 602 | signalDiv = document.getElementById("initial-load-signal"); |
| 603 | signalDiv.addEventListener("webkitAnimationStart", onContentReady, false); |
Andy Huang | bffc312 | 2012-10-05 21:20:56 -0700 | [diff] [blame] | 604 | } |
| 605 | } |
| 606 | |
Andy Huang | 2301470 | 2012-07-09 12:50:36 -0700 | [diff] [blame] | 607 | // BEGIN Java->JavaScript handlers |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 608 | function measurePositions() { |
Andy Huang | adbf3e8 | 2012-10-13 13:30:19 -0700 | [diff] [blame] | 609 | var overlayTops, overlayBottoms; |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 610 | var i; |
| 611 | var len; |
| 612 | |
Andy Huang | adbf3e8 | 2012-10-13 13:30:19 -0700 | [diff] [blame] | 613 | var expandedBody, headerSpacer; |
| 614 | var prevBodyBottom = 0; |
| 615 | var expandedBodyDivs = document.querySelectorAll(".expanded > .mail-message-content"); |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 616 | |
Andy Huang | adbf3e8 | 2012-10-13 13:30:19 -0700 | [diff] [blame] | 617 | // N.B. offsetTop and offsetHeight of an element with the "zoom:" style applied cannot be |
| 618 | // trusted. |
| 619 | |
| 620 | overlayTops = new Array(expandedBodyDivs.length + 1); |
| 621 | overlayBottoms = new Array(expandedBodyDivs.length + 1); |
| 622 | for (i = 0, len = expandedBodyDivs.length; i < len; i++) { |
| 623 | expandedBody = expandedBodyDivs[i]; |
| 624 | headerSpacer = expandedBody.previousElementSibling; |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 625 | // addJavascriptInterface handler only supports string arrays |
Andrew Sapperstein | 73bac14 | 2014-05-13 10:25:34 -0700 | [diff] [blame] | 626 | overlayTops[i] = prevBodyBottom; |
| 627 | overlayBottoms[i] = (getTotalOffset(headerSpacer).top + headerSpacer.offsetHeight); |
Andy Huang | adbf3e8 | 2012-10-13 13:30:19 -0700 | [diff] [blame] | 628 | prevBodyBottom = getTotalOffset(expandedBody.nextElementSibling).top; |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 629 | } |
Andy Huang | adbf3e8 | 2012-10-13 13:30:19 -0700 | [diff] [blame] | 630 | // add an extra one to mark the top/bottom of the last message footer spacer |
Andrew Sapperstein | 73bac14 | 2014-05-13 10:25:34 -0700 | [diff] [blame] | 631 | overlayTops[i] = prevBodyBottom; |
| 632 | overlayBottoms[i] = document.documentElement.scrollHeight; |
Andrew Sapperstein | e4e1c49 | 2013-08-20 17:54:57 -0700 | [diff] [blame] | 633 | |
Andy Huang | adbf3e8 | 2012-10-13 13:30:19 -0700 | [diff] [blame] | 634 | window.mail.onWebContentGeometryChange(overlayTops, overlayBottoms); |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 635 | } |
| 636 | |
Scott Kennedy | eb9a4bd | 2012-11-12 10:33:04 -0800 | [diff] [blame] | 637 | function unblockImages(messageDomIds) { |
| 638 | var i, j, images, imgCount, image, blockedSrc; |
| 639 | for (j = 0, len = messageDomIds.length; j < len; j++) { |
| 640 | var messageDomId = messageDomIds[j]; |
| 641 | var msg = document.getElementById(messageDomId); |
| 642 | if (!msg) { |
| 643 | console.log("can't unblock, no matching message for id: " + messageDomId); |
| 644 | continue; |
| 645 | } |
| 646 | images = msg.getElementsByTagName("img"); |
| 647 | for (i = 0, imgCount = images.length; i < imgCount; i++) { |
| 648 | image = images[i]; |
| 649 | blockedSrc = image.getAttribute(BLOCKED_SRC_ATTR); |
| 650 | if (blockedSrc) { |
| 651 | image.src = blockedSrc; |
| 652 | image.removeAttribute(BLOCKED_SRC_ATTR); |
| 653 | } |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 654 | } |
| 655 | } |
| 656 | } |
Andy Huang | c754357 | 2012-04-03 15:34:29 -0700 | [diff] [blame] | 657 | |
Mark Wei | ab2d998 | 2012-09-25 13:06:17 -0700 | [diff] [blame] | 658 | function setConversationHeaderSpacerHeight(spacerHeight) { |
| 659 | var spacer = document.getElementById("conversation-header"); |
| 660 | if (!spacer) { |
| 661 | console.log("can't set spacer for conversation header"); |
| 662 | return; |
| 663 | } |
| 664 | spacer.style.height = spacerHeight + "px"; |
| 665 | measurePositions(); |
| 666 | } |
| 667 | |
Andrew Sapperstein | 735a22a | 2014-07-11 03:57:42 -0700 | [diff] [blame] | 668 | function setConversationFooterSpacerHeight(spacerHeight) { |
| 669 | var spacer = document.getElementById("conversation-footer"); |
| 670 | if (!spacer) { |
| 671 | console.log("can't set spacer for conversation footer"); |
| 672 | return; |
| 673 | } |
| 674 | spacer.style.height = spacerHeight + "px"; |
| 675 | measurePositions(); |
| 676 | } |
| 677 | |
Andy Huang | c754357 | 2012-04-03 15:34:29 -0700 | [diff] [blame] | 678 | function setMessageHeaderSpacerHeight(messageDomId, spacerHeight) { |
| 679 | var spacer = document.querySelector("#" + messageDomId + " > .mail-message-header"); |
Andrew Sapperstein | 381c322 | 2014-04-20 12:23:57 -0700 | [diff] [blame] | 680 | setSpacerHeight(spacer, spacerHeight); |
| 681 | } |
| 682 | |
Andrew Sapperstein | 381c322 | 2014-04-20 12:23:57 -0700 | [diff] [blame] | 683 | function setSpacerHeight(spacer, spacerHeight) { |
Andy Huang | c754357 | 2012-04-03 15:34:29 -0700 | [diff] [blame] | 684 | if (!spacer) { |
| 685 | console.log("can't set spacer for message with id: " + messageDomId); |
| 686 | return; |
| 687 | } |
| 688 | spacer.style.height = spacerHeight + "px"; |
| 689 | measurePositions(); |
| 690 | } |
| 691 | |
Andrew Sapperstein | 59ccec3 | 2014-06-18 17:22:49 -0700 | [diff] [blame] | 692 | function setMessageBodyVisible(messageDomId, isVisible, spacerHeight) { |
Andy Huang | c754357 | 2012-04-03 15:34:29 -0700 | [diff] [blame] | 693 | var i, len; |
| 694 | var visibility = isVisible ? "block" : "none"; |
| 695 | var messageDiv = document.querySelector("#" + messageDomId); |
| 696 | var collapsibleDivs = document.querySelectorAll("#" + messageDomId + " > .collapsible"); |
| 697 | if (!messageDiv || collapsibleDivs.length == 0) { |
| 698 | console.log("can't set body visibility for message with id: " + messageDomId); |
| 699 | return; |
| 700 | } |
Andrew Sapperstein | cee3c90 | 2013-07-31 10:52:02 -0700 | [diff] [blame] | 701 | |
Andy Huang | c754357 | 2012-04-03 15:34:29 -0700 | [diff] [blame] | 702 | messageDiv.classList.toggle("expanded"); |
| 703 | for (i = 0, len = collapsibleDivs.length; i < len; i++) { |
| 704 | collapsibleDivs[i].style.display = visibility; |
| 705 | } |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 706 | |
| 707 | // revealing new content should trigger width normalization, since the initial render |
| 708 | // skips collapsed and super-collapsed messages |
| 709 | if (isVisible) { |
| 710 | normalizeElementWidths(messageDiv.getElementsByClassName("mail-message-content")); |
| 711 | } |
| 712 | |
Andy Huang | c754357 | 2012-04-03 15:34:29 -0700 | [diff] [blame] | 713 | setMessageHeaderSpacerHeight(messageDomId, spacerHeight); |
| 714 | } |
Andy Huang | 46dfba6 | 2012-04-19 01:47:32 -0700 | [diff] [blame] | 715 | |
| 716 | function replaceSuperCollapsedBlock(startIndex) { |
Andy Huang | f500db8 | 2012-10-23 16:56:27 -0700 | [diff] [blame] | 717 | var parent, block, msg; |
Andy Huang | 46dfba6 | 2012-04-19 01:47:32 -0700 | [diff] [blame] | 718 | |
| 719 | block = document.querySelector(".mail-super-collapsed-block[index='" + startIndex + "']"); |
| 720 | if (!block) { |
| 721 | console.log("can't expand super collapsed block at index: " + startIndex); |
| 722 | return; |
| 723 | } |
| 724 | parent = block.parentNode; |
| 725 | block.innerHTML = window.mail.getTempMessageBodies(); |
| 726 | |
Andy Huang | f500db8 | 2012-10-23 16:56:27 -0700 | [diff] [blame] | 727 | // process the new block contents in one go before we pluck them out of the common ancestor |
| 728 | processQuotedText(block, false /* showElided */); |
| 729 | hideUnsafeImages(block.getElementsByClassName("mail-message-content")); |
| 730 | |
| 731 | msg = block.firstChild; |
| 732 | while (msg) { |
| 733 | parent.insertBefore(msg, block); |
| 734 | msg = block.firstChild; |
Andy Huang | 46dfba6 | 2012-04-19 01:47:32 -0700 | [diff] [blame] | 735 | } |
| 736 | parent.removeChild(block); |
Ray Chen | d56ecc5 | 2014-09-03 16:31:07 +0200 | [diff] [blame] | 737 | disablePostForms(); |
Andy Huang | 46dfba6 | 2012-04-19 01:47:32 -0700 | [diff] [blame] | 738 | measurePositions(); |
| 739 | } |
mindyp | 3bcf180 | 2012-09-09 11:17:00 -0700 | [diff] [blame] | 740 | |
Andy Huang | 986776b | 2014-02-19 18:29:43 -0800 | [diff] [blame] | 741 | function processNewMessageBody(msgContentDiv) { |
| 742 | processQuotedText(msgContentDiv, true /* showElided */); |
| 743 | hideUnsafeImages([msgContentDiv]); |
| 744 | if (up(msgContentDiv, "mail-message").classList.contains("expanded")) { |
| 745 | normalizeElementWidths([msgContentDiv]); |
| 746 | } |
| 747 | } |
| 748 | |
Andy Huang | 014ea4c | 2012-09-25 14:50:54 -0700 | [diff] [blame] | 749 | function replaceMessageBodies(messageIds) { |
| 750 | var i; |
| 751 | var id; |
| 752 | var msgContentDiv; |
| 753 | |
| 754 | for (i = 0, len = messageIds.length; i < len; i++) { |
| 755 | id = messageIds[i]; |
| 756 | msgContentDiv = document.querySelector("#" + id + " > .mail-message-content"); |
| 757 | msgContentDiv.innerHTML = window.mail.getMessageBody(id); |
Andy Huang | 986776b | 2014-02-19 18:29:43 -0800 | [diff] [blame] | 758 | processNewMessageBody(msgContentDiv); |
Andy Huang | 014ea4c | 2012-09-25 14:50:54 -0700 | [diff] [blame] | 759 | } |
Ray Chen | d56ecc5 | 2014-09-03 16:31:07 +0200 | [diff] [blame] | 760 | disablePostForms(); |
Andy Huang | 91d782a | 2012-10-25 12:37:29 -0700 | [diff] [blame] | 761 | measurePositions(); |
Andy Huang | 014ea4c | 2012-09-25 14:50:54 -0700 | [diff] [blame] | 762 | } |
| 763 | |
Andy Huang | 06c0362 | 2012-10-22 18:59:45 -0700 | [diff] [blame] | 764 | // handle the special case of adding a single new message at the end of a conversation |
| 765 | function appendMessageHtml() { |
| 766 | var msg = document.createElement("div"); |
| 767 | msg.innerHTML = window.mail.getTempMessageBodies(); |
Andrew Sapperstein | 1f08223 | 2013-07-29 11:16:07 -0700 | [diff] [blame] | 768 | var body = msg.children[0]; // toss the outer div, it was just to render innerHTML into |
Andrew Sapperstein | e2a30e1 | 2014-07-02 22:36:56 -0700 | [diff] [blame] | 769 | document.body.insertBefore(body, document.getElementById("conversation-footer")); |
Andy Huang | 986776b | 2014-02-19 18:29:43 -0800 | [diff] [blame] | 770 | processNewMessageBody(body.querySelector(".mail-message-content")); |
Ray Chen | d56ecc5 | 2014-09-03 16:31:07 +0200 | [diff] [blame] | 771 | disablePostForms(); |
Andy Huang | 91d782a | 2012-10-25 12:37:29 -0700 | [diff] [blame] | 772 | measurePositions(); |
Andy Huang | 06c0362 | 2012-10-22 18:59:45 -0700 | [diff] [blame] | 773 | } |
| 774 | |
Ray Chen | d56ecc5 | 2014-09-03 16:31:07 +0200 | [diff] [blame] | 775 | function disablePostForms() { |
| 776 | var forms = document.getElementsByTagName('FORM'); |
| 777 | var i; |
| 778 | var j; |
| 779 | var elements; |
| 780 | |
| 781 | for (i = 0; i < forms.length; ++i) { |
| 782 | if (forms[i].method.toUpperCase() === 'POST') { |
| 783 | forms[i].onsubmit = function() { |
| 784 | alert(MSG_FORMS_ARE_DISABLED); |
| 785 | return false; |
| 786 | } |
Ray Chen | 0e627c5 | 2014-09-16 10:10:09 +0200 | [diff] [blame] | 787 | elements = forms[i].elements; |
Ray Chen | d56ecc5 | 2014-09-03 16:31:07 +0200 | [diff] [blame] | 788 | for (j = 0; j < elements.length; ++j) { |
Ray Chen | 3bd6421 | 2014-09-22 17:36:09 +0200 | [diff] [blame] | 789 | if (elements[j].type != 'submit') { |
| 790 | elements[j].disabled = true; |
| 791 | } |
Ray Chen | d56ecc5 | 2014-09-03 16:31:07 +0200 | [diff] [blame] | 792 | } |
| 793 | } |
| 794 | } |
| 795 | } |
Andy Huang | 3233bff | 2012-03-20 19:38:45 -0700 | [diff] [blame] | 796 | // END Java->JavaScript handlers |
| 797 | |
Andy Huang | 4cfe22a | 2012-10-15 18:20:33 -0700 | [diff] [blame] | 798 | // Do this first to ensure that the readiness signal comes through, |
| 799 | // even if a stray exception later occurs. |
| 800 | setupContentReady(); |
| 801 | |
Andy Huang | 014ea4c | 2012-09-25 14:50:54 -0700 | [diff] [blame] | 802 | collapseAllQuotedText(); |
Andy Huang | f500db8 | 2012-10-23 16:56:27 -0700 | [diff] [blame] | 803 | hideAllUnsafeImages(); |
Andy Huang | ffc725f | 2012-10-01 14:48:02 -0700 | [diff] [blame] | 804 | normalizeAllMessageWidths(); |
Andy Huang | 2301470 | 2012-07-09 12:50:36 -0700 | [diff] [blame] | 805 | //setWideViewport(); |
Andrew Sapperstein | 575e82b | 2014-04-07 16:44:11 -0700 | [diff] [blame] | 806 | // hack for b/1333356 |
| 807 | if (!RUNNING_KITKAT_OR_LATER) { |
| 808 | restoreScrollPosition(); |
| 809 | } |
Ray Chen | d56ecc5 | 2014-09-03 16:31:07 +0200 | [diff] [blame] | 810 | disablePostForms(); |
Andy Huang | f70fc40 | 2012-02-17 15:37:42 -0800 | [diff] [blame] | 811 | measurePositions(); |