script.js revision 4821bbb4aeaf4393e45575e0e43c7086521039ad
1f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang/* 2f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Copyright (C) 2012 Google Inc. 3f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Licensed to The Android Open Source Project. 4f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 5f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Licensed under the Apache License, Version 2.0 (the "License"); 6f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * you may not use this file except in compliance with the License. 7f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * You may obtain a copy of the License at 8f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 9f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * http://www.apache.org/licenses/LICENSE-2.0 10f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 11f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Unless required by applicable law or agreed to in writing, software 12f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * distributed under the License is distributed on an "AS IS" BASIS, 13f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * See the License for the specific language governing permissions and 15f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * limitations under the License. 16f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang */ 17f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 183233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huangvar BLOCKED_SRC_ATTR = "blocked-src"; 19f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 2063b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang// the set of Elements currently scheduled for processing in handleAllImageLoads 2163b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang// this is an Array, but we treat it like a Set and only insert unique items 2263b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huangvar gImageLoadElements = []; 2363b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang 2402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huangvar gScaleInfo; 2502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 26f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang/** 273a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang * Only revert transforms that do an imperfect job of shrinking content if they fail 283a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang * to shrink by this much. Expressed as a ratio of: 293a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang * (original width difference : width difference after transforms); 303a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang */ 310180f27c0998623b702274048b49cd4bec536cf1Andy HuangTRANSFORM_MINIMUM_EFFECTIVE_RATIO = 0.7; 323a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang 333a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang/** 34f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Returns the page offset of an element. 35f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 36f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * @param {Element} element The element to return the page offset for. 37f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * @return {left: number, top: number} A tuple including a left and top value representing 38f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * the page offset of the element. 39f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang */ 40f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangfunction getTotalOffset(el) { 41f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang var result = { 42f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang left: 0, 43f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang top: 0 44f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang }; 45f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang var parent = el; 46f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 47f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang while (parent) { 48f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang result.left += parent.offsetLeft; 49f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang result.top += parent.offsetTop; 50f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang parent = parent.offsetParent; 51f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 52f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 53f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang return result; 54f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang} 55f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 56ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang/** 57ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang * Walks up the DOM starting at a given element, and returns an element that has the 58ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang * specified class name or null. 59ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang */ 60ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huangfunction up(el, className) { 61ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang var parent = el; 62ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang while (parent) { 63ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang if (parent.classList && parent.classList.contains(className)) { 64ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang break; 65ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang } 66ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang parent = parent.parentNode; 67ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang } 68ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang return parent || null; 69ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang} 70ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang 7102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huangfunction getCachedValue(div, property, attrName) { 7202f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var value; 7302f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang if (div.hasAttribute(attrName)) { 7402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang value = div.getAttribute(attrName); 7502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang } else { 7602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang value = div[property]; 7702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang div.setAttribute(attrName, value); 7802f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang } 7902f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang return value; 8002f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang} 8102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 82df0d91c5fa064e93b647fd62fe2446791664003fAndy Huangfunction onToggleClick(e) { 83df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang toggleQuotedText(e.target); 84df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang measurePositions(); 85df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang} 86df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang 87df0d91c5fa064e93b647fd62fe2446791664003fAndy Huangfunction toggleQuotedText(toggleElement) { 88f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang var elidedTextElement = toggleElement.nextSibling; 89f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang var isHidden = getComputedStyle(elidedTextElement).display == 'none'; 90f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang toggleElement.innerHTML = isHidden ? MSG_HIDE_ELIDED : MSG_SHOW_ELIDED; 91f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang elidedTextElement.style.display = isHidden ? 'block' : 'none'; 92ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang 93ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang // Revealing the elided text should normalize it to fit-width to prevent 94ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang // this message from blowing out the conversation width. 95ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang if (isHidden) { 96ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang normalizeElementWidths([elidedTextElement]); 97ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang } 98f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang} 99f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 100014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huangfunction collapseAllQuotedText() { 101df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang processQuotedText(document.documentElement, false /* showElided */); 102014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang} 103014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang 104df0d91c5fa064e93b647fd62fe2446791664003fAndy Huangfunction processQuotedText(elt, showElided) { 105f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang var i; 106014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang var elements = elt.getElementsByClassName("elided-text"); 107f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang var elidedElement, toggleElement; 108f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang for (i = 0; i < elements.length; i++) { 109f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang elidedElement = elements[i]; 110f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang toggleElement = document.createElement("div"); 11182119afe5d596c69109ad9ce80e025dbec9ca4d1Andy Huang toggleElement.className = "mail-elided-text"; 112f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang toggleElement.innerHTML = MSG_SHOW_ELIDED; 113df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang toggleElement.onclick = onToggleClick; 114df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang elidedElement.style.display = 'none'; 115f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang elidedElement.parentNode.insertBefore(toggleElement, elidedElement); 116df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang if (showElided) { 117df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang toggleQuotedText(toggleElement); 118df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang } 119f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 120f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang} 121f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 1224cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huangfunction isConversationEmpty(bodyDivs) { 1234cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang var i, len; 1244cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang var msgBody; 1254cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang var text; 1264cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang 1274cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang // Check if given divs are empty (in appearance), and disable zoom if so. 1284cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang for (i = 0, len = bodyDivs.length; i < len; i++) { 1294cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang msgBody = bodyDivs[i]; 1304cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang // use 'textContent' to exclude markup when determining whether bodies are empty 1314cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang // (fall back to more expensive 'innerText' if 'textContent' isn't implemented) 1324cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang text = msgBody.textContent || msgBody.innerText; 1334cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang if (text.trim().length > 0) { 1344cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang return false; 1354cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang } 1364cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang } 1374cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang return true; 1384cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang} 1394cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang 140ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huangfunction normalizeAllMessageWidths() { 1414cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang var expandedBodyDivs; 1424cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang var metaViewport; 1434cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang var contentValues; 1444cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang var isEmpty; 1454cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang 1464cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang expandedBodyDivs = document.querySelectorAll(".expanded > .mail-message-content"); 1474cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang 1484cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang isEmpty = isConversationEmpty(expandedBodyDivs); 1494cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang 1504cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang normalizeElementWidths(expandedBodyDivs); 1514cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang 1524cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang // assemble a working <meta> viewport "content" value from the base value in the 1534cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang // document, plus any dynamically determined options 1544cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang metaViewport = document.getElementById("meta-viewport"); 1554cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang contentValues = [metaViewport.getAttribute("content")]; 1564cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang if (isEmpty) { 1574cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang contentValues.push(metaViewport.getAttribute("data-zoom-off")); 1584cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang } else { 1594cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang contentValues.push(metaViewport.getAttribute("data-zoom-on")); 1604cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang } 1614cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang metaViewport.setAttribute("content", contentValues.join(",")); 162ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang} 163ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang 164ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang/* 165ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang * Normalizes the width of all elements supplied to the document body's overall width. 166ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang * Narrower elements are zoomed in, and wider elements are zoomed out. 167ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang * This method is idempotent. 168ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang */ 169ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huangfunction normalizeElementWidths(elements) { 170f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang var i; 171ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang var el; 172adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang var documentWidth; 173ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang var newZoom, oldZoom; 174256b35c0a8287f48c28e0d1ba3fae65790063295Andy Huang 175adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang documentWidth = document.body.offsetWidth; 176adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang 177f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang for (i = 0; i < elements.length; i++) { 178ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang el = elements[i]; 179ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang oldZoom = el.style.zoom; 180ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang // reset any existing normalization 181ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang if (oldZoom) { 182ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang el.style.zoom = 1; 183ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang } 184ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang newZoom = documentWidth / el.scrollWidth; 1850180f27c0998623b702274048b49cd4bec536cf1Andy Huang transformContent(el, documentWidth, el.scrollWidth); 1865ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang newZoom = documentWidth / el.scrollWidth; 1875ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang if (NORMALIZE_MESSAGE_WIDTHS) { 1885ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang el.style.zoom = newZoom; 1895ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang } 1905ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang } 1915ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang} 1925ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang 1930180f27c0998623b702274048b49cd4bec536cf1Andy Huangfunction transformContent(el, docWidth, elWidth) { 1945ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang var nodes; 1955ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang var i, len; 1960180f27c0998623b702274048b49cd4bec536cf1Andy Huang var index; 1973a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang var newWidth = elWidth; 1985ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang var wStr; 1993a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang var touched; 2000180f27c0998623b702274048b49cd4bec536cf1Andy Huang // the format of entries in this array is: 2010180f27c0998623b702274048b49cd4bec536cf1Andy Huang // entry := [ undoFunction, undoFunctionThis, undoFunctionParamArray ] 2023a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang var actionLog = []; 2033a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang var node; 2043a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang var start; 2055ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang if (elWidth <= docWidth) { 2065ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang return; 2075ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang } 2083a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang 2093a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang start = Date.now(); 2103a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang // Try munging all divs with inline styles where the width 2113a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang // is wider than docWidth, and change it to be a max-width. 2123a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang touched = false; 2130180f27c0998623b702274048b49cd4bec536cf1Andy Huang nodes = ENABLE_MUNGE_TABLES ? el.querySelectorAll("div[style]") : []; 2145ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang for (i = 0, len = nodes.length; i < len; i++) { 2153a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang node = nodes[i]; 2163a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang wStr = node.style.width; 2170180f27c0998623b702274048b49cd4bec536cf1Andy Huang index = wStr ? wStr.indexOf("px") : -1; 2180180f27c0998623b702274048b49cd4bec536cf1Andy Huang if (index >= 0 && wStr.slice(0, index) > docWidth) { 2193a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang node.style.width = ""; 2203a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang node.style.maxWidth = wStr; 2215ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang touched = true; 2220180f27c0998623b702274048b49cd4bec536cf1Andy Huang // TODO: add this to the actionLog 2230180f27c0998623b702274048b49cd4bec536cf1Andy Huang // (not a huge deal if this is missing because it's fairly non-destructive) 2245ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang } 2255ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang } 2265ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang if (touched) { 2275ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang newWidth = el.scrollWidth; 2283a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang console.log("ran div-width munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth 2293a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang + " docW=" + docWidth); 2303a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang if (newWidth <= docWidth) { 2313a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang console.log("munger succeeded, elapsed time=" + (Date.now() - start)); 2323a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang return; 2333a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang } 2343a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang } 2353a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang 2360180f27c0998623b702274048b49cd4bec536cf1Andy Huang // OK, that wasn't enough. Find images with widths and override their widths. 2370180f27c0998623b702274048b49cd4bec536cf1Andy Huang nodes = ENABLE_MUNGE_IMAGES ? el.querySelectorAll("img") : []; 2380180f27c0998623b702274048b49cd4bec536cf1Andy Huang touched = transformImages(nodes, docWidth, actionLog); 2390180f27c0998623b702274048b49cd4bec536cf1Andy Huang if (touched) { 2400180f27c0998623b702274048b49cd4bec536cf1Andy Huang newWidth = el.scrollWidth; 2410180f27c0998623b702274048b49cd4bec536cf1Andy Huang console.log("ran img munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth 2420180f27c0998623b702274048b49cd4bec536cf1Andy Huang + " docW=" + docWidth); 2430180f27c0998623b702274048b49cd4bec536cf1Andy Huang if (newWidth <= docWidth) { 2440180f27c0998623b702274048b49cd4bec536cf1Andy Huang console.log("munger succeeded, elapsed time=" + (Date.now() - start)); 2450180f27c0998623b702274048b49cd4bec536cf1Andy Huang return; 2460180f27c0998623b702274048b49cd4bec536cf1Andy Huang } 2470180f27c0998623b702274048b49cd4bec536cf1Andy Huang } 2480180f27c0998623b702274048b49cd4bec536cf1Andy Huang 2493a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang // OK, that wasn't enough. Find tables with widths and override their widths. 2500180f27c0998623b702274048b49cd4bec536cf1Andy Huang nodes = ENABLE_MUNGE_TABLES ? el.querySelectorAll("table") : []; 2510180f27c0998623b702274048b49cd4bec536cf1Andy Huang touched = addClassToElements(nodes, shouldMungeTable, "munged", 2523a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang actionLog); 2533a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang if (touched) { 2543a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang newWidth = el.scrollWidth; 2555ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang console.log("ran table munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth 2565ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang + " docW=" + docWidth); 2575ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang if (newWidth <= docWidth) { 2583a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang console.log("munger succeeded, elapsed time=" + (Date.now() - start)); 2595ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang return; 2605ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang } 261f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 2625ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang 2633a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang // OK, that wasn't enough. Try munging all <td> to override any width and nowrap set. 2640180f27c0998623b702274048b49cd4bec536cf1Andy Huang nodes = ENABLE_MUNGE_TABLES ? el.querySelectorAll("td") : []; 2650180f27c0998623b702274048b49cd4bec536cf1Andy Huang touched = addClassToElements(nodes, null /* mungeAll */, "munged", 2663a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang actionLog); 2673a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang if (touched) { 2683a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang newWidth = el.scrollWidth; 2693a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang console.log("ran td munger on el=" + el + " oldW=" + elWidth + " newW=" + newWidth 2703a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang + " docW=" + docWidth); 2713a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang if (newWidth <= docWidth) { 2723a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang console.log("munger succeeded, elapsed time=" + (Date.now() - start)); 2733a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang return; 2745ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang } 2755ea5a8330532a75c83cbb30993a14ee9b821fa2aAndy Huang } 2763a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang 2773a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang // If the transformations shrank the width significantly enough, leave them in place. 2783a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang // We figure that in those cases, the benefits outweight the risk of rendering artifacts. 2793a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang if ((elWidth - newWidth) / (elWidth - docWidth) > TRANSFORM_MINIMUM_EFFECTIVE_RATIO) { 2803a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang console.log("transform(s) deemed effective enough. elapsed time=" 2813a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang + (Date.now() - start)); 2823a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang return; 2833a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang } 2843a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang 2853a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang // reverse all changes if the width is STILL not narrow enough 2863a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang // (except the width->maxWidth change, which is not particularly destructive) 2873a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang for (i = 0, len = actionLog.length; i < len; i++) { 2880180f27c0998623b702274048b49cd4bec536cf1Andy Huang actionLog[i][0].apply(actionLog[i][1], actionLog[i][2]); 2893a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang } 2903a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang if (actionLog.length > 0) { 2913a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang console.log("all mungers failed, changes reversed. elapsed time=" + (Date.now() - start)); 2923a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang } 2933a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang} 2943a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang 2953a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huangfunction addClassToElements(nodes, conditionFn, classToAdd, actionLog) { 2963a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang var i, len; 2973a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang var node; 2983a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang var added = false; 2993a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang for (i = 0, len = nodes.length; i < len; i++) { 3003a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang node = nodes[i]; 3013a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang if (!conditionFn || conditionFn(node)) { 3024821bbb4aeaf4393e45575e0e43c7086521039adAndy Huang if (node.classList.contains(classToAdd)) { 3034821bbb4aeaf4393e45575e0e43c7086521039adAndy Huang continue; 3044821bbb4aeaf4393e45575e0e43c7086521039adAndy Huang } 3053a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang node.classList.add(classToAdd); 3063a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang added = true; 3070180f27c0998623b702274048b49cd4bec536cf1Andy Huang actionLog.push([node.classList.remove, node.classList, [classToAdd]]); 3083a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang } 3093a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang } 3103a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang return added; 3113a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang} 3123a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang 3130180f27c0998623b702274048b49cd4bec536cf1Andy Huangfunction transformImages(nodes, docWidth, actionLog) { 3140180f27c0998623b702274048b49cd4bec536cf1Andy Huang var i, len; 3150180f27c0998623b702274048b49cd4bec536cf1Andy Huang var node; 3160180f27c0998623b702274048b49cd4bec536cf1Andy Huang var w, h; 3170180f27c0998623b702274048b49cd4bec536cf1Andy Huang var touched = false; 3180180f27c0998623b702274048b49cd4bec536cf1Andy Huang 3190180f27c0998623b702274048b49cd4bec536cf1Andy Huang for (i = 0, len = nodes.length; i < len; i++) { 3200180f27c0998623b702274048b49cd4bec536cf1Andy Huang node = nodes[i]; 3210180f27c0998623b702274048b49cd4bec536cf1Andy Huang w = node.offsetWidth; 3220180f27c0998623b702274048b49cd4bec536cf1Andy Huang h = node.offsetHeight; 3230180f27c0998623b702274048b49cd4bec536cf1Andy Huang // shrink w/h proportionally if the img is wider than available width 3240180f27c0998623b702274048b49cd4bec536cf1Andy Huang if (w > docWidth) { 3250180f27c0998623b702274048b49cd4bec536cf1Andy Huang node.setAttribute("data-savedMaxWidth", node.style.maxWidth); 3260180f27c0998623b702274048b49cd4bec536cf1Andy Huang node.setAttribute("data-savedWidth", node.style.width); 3270180f27c0998623b702274048b49cd4bec536cf1Andy Huang node.setAttribute("data-savedHeight", node.style.height); 3280180f27c0998623b702274048b49cd4bec536cf1Andy Huang node.style.maxWidth = docWidth + "px"; 3290180f27c0998623b702274048b49cd4bec536cf1Andy Huang node.style.width = "100%"; 3300180f27c0998623b702274048b49cd4bec536cf1Andy Huang node.style.height = "auto"; 3310180f27c0998623b702274048b49cd4bec536cf1Andy Huang actionLog.push([undoSetProperty, node, ["maxWidth", "data-savedMaxWidth"]]); 3320180f27c0998623b702274048b49cd4bec536cf1Andy Huang actionLog.push([undoSetProperty, node, ["width", "data-savedWidth"]]); 3330180f27c0998623b702274048b49cd4bec536cf1Andy Huang actionLog.push([undoSetProperty, node, ["height", "data-savedHeight"]]); 3340180f27c0998623b702274048b49cd4bec536cf1Andy Huang touched = true; 3350180f27c0998623b702274048b49cd4bec536cf1Andy Huang } 3360180f27c0998623b702274048b49cd4bec536cf1Andy Huang } 3370180f27c0998623b702274048b49cd4bec536cf1Andy Huang return touched; 3380180f27c0998623b702274048b49cd4bec536cf1Andy Huang} 3390180f27c0998623b702274048b49cd4bec536cf1Andy Huang 3400180f27c0998623b702274048b49cd4bec536cf1Andy Huangfunction undoSetProperty(property, savedProperty) { 3410180f27c0998623b702274048b49cd4bec536cf1Andy Huang this.style[property] = savedProperty ? this.getAttribute(savedProperty) : ""; 3420180f27c0998623b702274048b49cd4bec536cf1Andy Huang} 3430180f27c0998623b702274048b49cd4bec536cf1Andy Huang 3443a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huangfunction shouldMungeTable(table) { 3453a398b245930ce60ceb51fc605ab0f20c8df1f62Andy Huang return table.hasAttribute("width") || table.style.width; 346f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang} 347f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 348f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huangfunction hideAllUnsafeImages() { 349f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang hideUnsafeImages(document.getElementsByClassName("mail-message-content")); 350f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang} 351f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang 352f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huangfunction hideUnsafeImages(msgContentDivs) { 353f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang var i, msgContentCount; 3543233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang var j, imgCount; 355f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang var msgContentDiv, image; 3563233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang var images; 3573233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang var showImages; 358f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang for (i = 0, msgContentCount = msgContentDivs.length; i < msgContentCount; i++) { 359f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang msgContentDiv = msgContentDivs[i]; 360f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang showImages = msgContentDiv.classList.contains("mail-show-images"); 3613233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang 362f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang images = msgContentDiv.getElementsByTagName("img"); 3633233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang for (j = 0, imgCount = images.length; j < imgCount; j++) { 3643233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang image = images[j]; 36541dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook rewriteRelativeImageSrc(image); 3663233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang attachImageLoadListener(image); 3673233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang // TODO: handle inline image attachments for all supported protocols 3683233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang if (!showImages) { 3693233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang blockImage(image); 3703233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang } 3713233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang } 3723233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang } 3733233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang} 3743233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang 37541dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook/** 37641dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook * Changes relative paths to absolute path by pre-pending the account uri 37741dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook * @param {Element} imgElement Image for which the src path will be updated. 37841dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook */ 37941dca185f7683b36bdafd9520c0648c897a95834Paul Westbrookfunction rewriteRelativeImageSrc(imgElement) { 38041dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook var src = imgElement.src; 381cebcc64fbd69618ff89f9fac0bfe9b9e7d7ce104Paul Westbrook 382cebcc64fbd69618ff89f9fac0bfe9b9e7d7ce104Paul Westbrook // DOC_BASE_URI will always be a unique x-thread:// uri for this particular conversation 383cebcc64fbd69618ff89f9fac0bfe9b9e7d7ce104Paul Westbrook if (src.indexOf(DOC_BASE_URI) == 0 && (DOC_BASE_URI != CONVERSATION_BASE_URI)) { 384cebcc64fbd69618ff89f9fac0bfe9b9e7d7ce104Paul Westbrook // The conversation specifies a different base uri than the document 385cebcc64fbd69618ff89f9fac0bfe9b9e7d7ce104Paul Westbrook src = CONVERSATION_BASE_URI + src.substring(DOC_BASE_URI.length); 386cebcc64fbd69618ff89f9fac0bfe9b9e7d7ce104Paul Westbrook imgElement.src = src; 38741dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook } 38841dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook}; 38941dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook 39041dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook 3913233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huangfunction attachImageLoadListener(imageElement) { 3923233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang // Reset the src attribute to the empty string because onload will only fire if the src 3933233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang // attribute is set after the onload listener. 3943233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang var originalSrc = imageElement.src; 3953233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang imageElement.src = ''; 396ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang imageElement.onload = imageOnLoad; 3973233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang imageElement.src = originalSrc; 3983233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang} 3993233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang 40063b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang/** 40163b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang * Handle an onload event for an <img> tag. 40263b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang * The image could be within an elided-text block, or at the top level of a message. 40363b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang * When a new image loads, its new bounds may affect message or elided-text geometry, 40463b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang * so we need to inspect and adjust the enclosing element's zoom level where necessary. 40563b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang * 40663b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang * Because this method can be called really often, and zoom-level adjustment is slow, 40763b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang * we collect the elements to be processed and do them all later in a single deferred pass. 40863b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang */ 409ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huangfunction imageOnLoad(e) { 410ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang // normalize the quoted text parent if we're in a quoted text block, or else 411ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang // normalize the parent message content element 412ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang var parent = up(e.target, "elided-text") || up(e.target, "mail-message-content"); 41363b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang if (!parent) { 41463b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang // sanity check. shouldn't really happen. 41563b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang return; 41663b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang } 41763b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang 41863b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang // if there was no previous work, schedule a new deferred job 41963b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang if (gImageLoadElements.length == 0) { 42063b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang window.setTimeout(handleAllImageOnLoads, 0); 42163b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang } 42263b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang 42363b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang // enqueue the work if it wasn't already enqueued 42463b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang if (gImageLoadElements.indexOf(parent) == -1) { 42563b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang gImageLoadElements.push(parent); 426ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang } 42763b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang} 42863b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang 42963b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang// handle all deferred work from image onload events 43063b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huangfunction handleAllImageOnLoads() { 43163b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang normalizeElementWidths(gImageLoadElements); 432ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang measurePositions(); 43363b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang // clear the queue so the next onload event starts a new job 43463b3c6725d60386f564ab53e3ba6495f0c158d9bAndy Huang gImageLoadElements = []; 435ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang} 436ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang 4373233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huangfunction blockImage(imageElement) { 4383233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang var src = imageElement.src; 43941dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook if (src.indexOf("http://") == 0 || src.indexOf("https://") == 0 || 44041dca185f7683b36bdafd9520c0648c897a95834Paul Westbrook src.indexOf("content://") == 0) { 4413233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang imageElement.setAttribute(BLOCKED_SRC_ATTR, src); 4423233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang imageElement.src = "data:"; 4433233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang } 4443233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang} 4453233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang 44623014705ca9872cd5004a1aa76e83ae260165ecaAndy Huangfunction setWideViewport() { 44723014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang var metaViewport = document.getElementById('meta-viewport'); 44823014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang metaViewport.setAttribute('content', 'width=' + WIDE_VIEWPORT_WIDTH); 44923014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang} 45023014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang 451e964eeec3a088b3f4c29b68d41f99e43a321ac52Andy Huangfunction restoreScrollPosition() { 452e964eeec3a088b3f4c29b68d41f99e43a321ac52Andy Huang var scrollYPercent = window.mail.getScrollYPercent(); 453e964eeec3a088b3f4c29b68d41f99e43a321ac52Andy Huang if (scrollYPercent && document.body.offsetHeight > window.innerHeight) { 454e964eeec3a088b3f4c29b68d41f99e43a321ac52Andy Huang document.body.scrollTop = Math.floor(scrollYPercent * document.body.offsetHeight); 455e964eeec3a088b3f4c29b68d41f99e43a321ac52Andy Huang } 456e964eeec3a088b3f4c29b68d41f99e43a321ac52Andy Huang} 457e964eeec3a088b3f4c29b68d41f99e43a321ac52Andy Huang 458bffc312614505b923f0054fde20d015bd21112cfAndy Huangfunction onContentReady(event) { 459bffc312614505b923f0054fde20d015bd21112cfAndy Huang window.mail.onContentReady(); 460bffc312614505b923f0054fde20d015bd21112cfAndy Huang} 461bffc312614505b923f0054fde20d015bd21112cfAndy Huang 462bffc312614505b923f0054fde20d015bd21112cfAndy Huangfunction setupContentReady() { 463bffc312614505b923f0054fde20d015bd21112cfAndy Huang var signalDiv; 464bffc312614505b923f0054fde20d015bd21112cfAndy Huang 465bffc312614505b923f0054fde20d015bd21112cfAndy Huang // PAGE READINESS SIGNAL FOR JELLYBEAN AND NEWER 466bffc312614505b923f0054fde20d015bd21112cfAndy Huang // Notify the app on 'webkitAnimationStart' of a simple dummy element with a simple no-op 467bffc312614505b923f0054fde20d015bd21112cfAndy Huang // animation that immediately runs on page load. The app uses this as a signal that the 468bffc312614505b923f0054fde20d015bd21112cfAndy Huang // content is loaded and ready to draw, since WebView delays firing this event until the 469bffc312614505b923f0054fde20d015bd21112cfAndy Huang // layers are composited and everything is ready to draw. 470bffc312614505b923f0054fde20d015bd21112cfAndy Huang // 471bffc312614505b923f0054fde20d015bd21112cfAndy Huang // This code is conditionally enabled on JB+ by setting the ENABLE_CONTENT_READY flag. 472bffc312614505b923f0054fde20d015bd21112cfAndy Huang if (ENABLE_CONTENT_READY) { 473bffc312614505b923f0054fde20d015bd21112cfAndy Huang signalDiv = document.getElementById("initial-load-signal"); 474bffc312614505b923f0054fde20d015bd21112cfAndy Huang signalDiv.addEventListener("webkitAnimationStart", onContentReady, false); 475bffc312614505b923f0054fde20d015bd21112cfAndy Huang } 476bffc312614505b923f0054fde20d015bd21112cfAndy Huang} 477bffc312614505b923f0054fde20d015bd21112cfAndy Huang 47823014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang// BEGIN Java->JavaScript handlers 479f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangfunction measurePositions() { 480adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang var overlayTops, overlayBottoms; 481f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang var i; 482f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang var len; 483f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 484adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang var expandedBody, headerSpacer; 485adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang var prevBodyBottom = 0; 486adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang var expandedBodyDivs = document.querySelectorAll(".expanded > .mail-message-content"); 487adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang 488adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang // N.B. offsetTop and offsetHeight of an element with the "zoom:" style applied cannot be 489adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang // trusted. 490f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 491adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang overlayTops = new Array(expandedBodyDivs.length + 1); 492adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang overlayBottoms = new Array(expandedBodyDivs.length + 1); 493adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang for (i = 0, len = expandedBodyDivs.length; i < len; i++) { 494adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang expandedBody = expandedBodyDivs[i]; 495adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang headerSpacer = expandedBody.previousElementSibling; 496f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang // addJavascriptInterface handler only supports string arrays 497adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang overlayTops[i] = "" + prevBodyBottom; 498adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang overlayBottoms[i] = "" + (getTotalOffset(headerSpacer).top + headerSpacer.offsetHeight); 499adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang prevBodyBottom = getTotalOffset(expandedBody.nextElementSibling).top; 500f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 501adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang // add an extra one to mark the top/bottom of the last message footer spacer 502adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang overlayTops[i] = "" + prevBodyBottom; 5037bdc3750454efe59617b7df945eadd7e59bee954Andy Huang overlayBottoms[i] = "" + document.body.offsetHeight; 504f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 505adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang window.mail.onWebContentGeometryChange(overlayTops, overlayBottoms); 506f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang} 507f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 508eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedyfunction unblockImages(messageDomIds) { 509eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy var i, j, images, imgCount, image, blockedSrc; 510eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy for (j = 0, len = messageDomIds.length; j < len; j++) { 511eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy var messageDomId = messageDomIds[j]; 512eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy var msg = document.getElementById(messageDomId); 513eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy if (!msg) { 514eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy console.log("can't unblock, no matching message for id: " + messageDomId); 515eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy continue; 516eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy } 517eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy images = msg.getElementsByTagName("img"); 518eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy for (i = 0, imgCount = images.length; i < imgCount; i++) { 519eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy image = images[i]; 520eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy blockedSrc = image.getAttribute(BLOCKED_SRC_ATTR); 521eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy if (blockedSrc) { 522eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy image.src = blockedSrc; 523eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy image.removeAttribute(BLOCKED_SRC_ATTR); 524eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy } 5253233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang } 5263233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang } 5273233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang} 528c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang 529ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Weifunction setConversationHeaderSpacerHeight(spacerHeight) { 530ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Wei var spacer = document.getElementById("conversation-header"); 531ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Wei if (!spacer) { 532ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Wei console.log("can't set spacer for conversation header"); 533ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Wei return; 534ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Wei } 535ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Wei spacer.style.height = spacerHeight + "px"; 536ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Wei measurePositions(); 537ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Wei} 538ab2d998506c83e82ddae25b6ba1419414e1e8122Mark Wei 539c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huangfunction setMessageHeaderSpacerHeight(messageDomId, spacerHeight) { 540c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang var spacer = document.querySelector("#" + messageDomId + " > .mail-message-header"); 541c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang if (!spacer) { 542c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang console.log("can't set spacer for message with id: " + messageDomId); 543c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang return; 544c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang } 545c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang spacer.style.height = spacerHeight + "px"; 546c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang measurePositions(); 547c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang} 548c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang 549c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huangfunction setMessageBodyVisible(messageDomId, isVisible, spacerHeight) { 550c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang var i, len; 551c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang var visibility = isVisible ? "block" : "none"; 552c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang var messageDiv = document.querySelector("#" + messageDomId); 553c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang var collapsibleDivs = document.querySelectorAll("#" + messageDomId + " > .collapsible"); 554c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang if (!messageDiv || collapsibleDivs.length == 0) { 555c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang console.log("can't set body visibility for message with id: " + messageDomId); 556c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang return; 557c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang } 558c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang messageDiv.classList.toggle("expanded"); 559c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang for (i = 0, len = collapsibleDivs.length; i < len; i++) { 560c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang collapsibleDivs[i].style.display = visibility; 561c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang } 562ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang 563ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang // revealing new content should trigger width normalization, since the initial render 564ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang // skips collapsed and super-collapsed messages 565ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang if (isVisible) { 566ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang normalizeElementWidths(messageDiv.getElementsByClassName("mail-message-content")); 567ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang } 568ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy Huang 569c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang setMessageHeaderSpacerHeight(messageDomId, spacerHeight); 570c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang} 57146dfba6160b55a582b344328067e3dafeb881dd9Andy Huang 57246dfba6160b55a582b344328067e3dafeb881dd9Andy Huangfunction replaceSuperCollapsedBlock(startIndex) { 573f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang var parent, block, msg; 57446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang 57546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang block = document.querySelector(".mail-super-collapsed-block[index='" + startIndex + "']"); 57646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang if (!block) { 57746dfba6160b55a582b344328067e3dafeb881dd9Andy Huang console.log("can't expand super collapsed block at index: " + startIndex); 57846dfba6160b55a582b344328067e3dafeb881dd9Andy Huang return; 57946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang } 58046dfba6160b55a582b344328067e3dafeb881dd9Andy Huang parent = block.parentNode; 58146dfba6160b55a582b344328067e3dafeb881dd9Andy Huang block.innerHTML = window.mail.getTempMessageBodies(); 58246dfba6160b55a582b344328067e3dafeb881dd9Andy Huang 583f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang // process the new block contents in one go before we pluck them out of the common ancestor 584f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang processQuotedText(block, false /* showElided */); 585f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang hideUnsafeImages(block.getElementsByClassName("mail-message-content")); 586f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang 587f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang msg = block.firstChild; 588f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang while (msg) { 589f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang parent.insertBefore(msg, block); 590f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang msg = block.firstChild; 59146dfba6160b55a582b344328067e3dafeb881dd9Andy Huang } 59246dfba6160b55a582b344328067e3dafeb881dd9Andy Huang parent.removeChild(block); 59346dfba6160b55a582b344328067e3dafeb881dd9Andy Huang measurePositions(); 59446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang} 5953bcf180f8104bc27319086a9a6ece5a3c2917c37mindyp 596014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huangfunction replaceMessageBodies(messageIds) { 597014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang var i; 598014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang var id; 599014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang var msgContentDiv; 600014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang 601014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang for (i = 0, len = messageIds.length; i < len; i++) { 602014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang id = messageIds[i]; 603014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang msgContentDiv = document.querySelector("#" + id + " > .mail-message-content"); 604014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang msgContentDiv.innerHTML = window.mail.getMessageBody(id); 605df0d91c5fa064e93b647fd62fe2446791664003fAndy Huang processQuotedText(msgContentDiv, true /* showElided */); 606f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang hideUnsafeImages([msgContentDiv]); 607014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang } 60891d782abc8015bd651fb5d0252b4d1ef369ec57bAndy Huang measurePositions(); 609014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang} 610014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang 61106c0362f59437f3ea2b5832272fb66158bb4b8c0Andy Huang// handle the special case of adding a single new message at the end of a conversation 61206c0362f59437f3ea2b5832272fb66158bb4b8c0Andy Huangfunction appendMessageHtml() { 61306c0362f59437f3ea2b5832272fb66158bb4b8c0Andy Huang var msg = document.createElement("div"); 61406c0362f59437f3ea2b5832272fb66158bb4b8c0Andy Huang msg.innerHTML = window.mail.getTempMessageBodies(); 61506c0362f59437f3ea2b5832272fb66158bb4b8c0Andy Huang msg = msg.children[0]; // toss the outer div, it was just to render innerHTML into 61606c0362f59437f3ea2b5832272fb66158bb4b8c0Andy Huang document.body.appendChild(msg); 61706c0362f59437f3ea2b5832272fb66158bb4b8c0Andy Huang processQuotedText(msg, true /* showElided */); 618f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy Huang hideUnsafeImages(msg.getElementsByClassName("mail-message-content")); 61991d782abc8015bd651fb5d0252b4d1ef369ec57bAndy Huang measurePositions(); 62006c0362f59437f3ea2b5832272fb66158bb4b8c0Andy Huang} 62106c0362f59437f3ea2b5832272fb66158bb4b8c0Andy Huang 62202f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huangfunction onScaleBegin(screenX, screenY) { 62302f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang// console.log("JS got scaleBegin x/y=" + screenX + "/" + screenY); 62402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var focusX = screenX + document.body.scrollLeft; 62502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var focusY = screenY + document.body.scrollTop; 62602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var i, len; 62702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var msgDivs = document.getElementsByClassName("mail-message"); 62802f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var msgDiv, msgBodyDiv; 62902f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var msgTop, msgDivTop, nextMsgTop; 63002f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var initialH; 63102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var initialScale; 63202f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var scaledOriginX, scaledOriginY; 63302f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var translateX, translateY; 63402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var origin; 63502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 63602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang gScaleInfo = undefined; 63702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 63802f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang for (i = 0, len = msgDivs.length; i < len; i++) { 63902f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgDiv = msgDivs[i]; 64002f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgTop = nextMsgTop ? nextMsgTop : getTotalOffset(msgDiv).top; 64102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang nextMsgTop = (i < len-1) ? getTotalOffset(msgDivs[i+1]).top : document.body.offsetHeight; 64202f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang if (focusY >= msgTop && focusY < nextMsgTop) { 64302f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgBodyDiv = msgDiv.children[1]; 64402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang initialScale = msgBodyDiv.getAttribute("data-initial-scale") || 1.0; 64502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 64602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgDivTop = getTotalOffset(msgBodyDiv).top; 64702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 648ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang // TODO: correct only for no initial translation 649ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang // FIXME: wrong for initialScale > 1.0 650ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang scaledOriginX = focusX / initialScale; 651ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang scaledOriginY = (focusY - msgDivTop) / initialScale; 65202f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 653ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang // TODO: is this still needed? 654ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang translateX = 0; 655ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang translateY = 0; 65602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 65702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang gScaleInfo = { 65802f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang div: msgBodyDiv, 65902f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang initialScale: initialScale, 660ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang initialScreenX: screenX, 661ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang initialScreenY: screenY, 662ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang originX: scaledOriginX, 663ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang originY: scaledOriginY, 66402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang translateX: translateX, 66502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang translateY: translateY, 66602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang initialH: getCachedValue(msgBodyDiv, "offsetHeight", "data-initial-height"), 66702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang minScale: Math.min(document.body.offsetWidth / msgBodyDiv.scrollWidth, 1.0), 668ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang currScale: initialScale, 669ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang currTranslateX: 0, 670ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang currTranslateY: 0 67102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang }; 67202f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 67302f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang origin = scaledOriginX + "px " + scaledOriginY + "px"; 67402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgBodyDiv.classList.add("zooming-focused"); 67502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgBodyDiv.style.webkitTransformOrigin = origin; 67602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgBodyDiv.style.webkitTransform = "scale3d(" + initialScale + "," + initialScale 67702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang + ",1) translate3d(" + translateX + "px," + translateY + "px,0)"; 67802f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang// console.log("scaleBegin, h=" + gScaleInfo.initialH + " origin='" + origin + "'"); 67902f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang break; 68002f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang } 68102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang } 68202f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang} 68302f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 68402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huangfunction onScaleEnd(screenX, screenY) { 68502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var msgBodyDiv; 68602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var scale; 68702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var h; 68802f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang if (!gScaleInfo) { 68902f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang return; 69002f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang } 69102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 69202f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang// console.log("JS got scaleEnd x/y=" + screenX + "/" + screenY); 69302f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgBodyDiv = gScaleInfo.div; 69402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang scale = gScaleInfo.currScale; 69502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgBodyDiv.style.webkitTransformOrigin = "0 0"; 69602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang // clear any translate 69702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang // switching to a 2D transform here re-renders the fonts more clearly, but introduces 69802f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang // texture upload lag to any subsequent scale operation 699ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang // TODO: conditionalize this based on device GPU performance and/or body size/complexity? 700ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang if (true) { 701ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang msgBodyDiv.style.webkitTransform = "scale(" + gScaleInfo.currScale + ")"; 702ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang } else { 703ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang msgBodyDiv.style.webkitTransform = "scale3d(" + scale + "," + scale + ",1)"; 704ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang } 70502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang h = gScaleInfo.initialH * scale; 70602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang// console.log("onScaleEnd set h=" + h); 70702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgBodyDiv.style.height = h + "px"; 708ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang 709ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang // Use saved translateX/Y rather than calculating from screenX/Y because screenX/Y values 710ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang // from onScaleEnd only track focus of remaining pointers, which is not useful and leads 711ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang // to a perceived jump. 712ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang var deltaScrollX = (scale - 1) * gScaleInfo.originX - gScaleInfo.currTranslateX; 713ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang var deltaScrollY = (scale - 1) * gScaleInfo.originY - gScaleInfo.currTranslateY; 714ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang// console.log("JS adjusting scroll by x/y=" + deltaScrollX + "/" + deltaScrollY); 715ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang 71602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgBodyDiv.classList.remove("zooming-focused"); 71702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang msgBodyDiv.setAttribute("data-initial-scale", scale); 7184c54e3627861351c6c5f74dd5132da7d0321377aAndy Huang 7194c54e3627861351c6c5f74dd5132da7d0321377aAndy Huang // TODO: is there a better way to make this more reliable? 7204c54e3627861351c6c5f74dd5132da7d0321377aAndy Huang window.setTimeout(function() { 7214c54e3627861351c6c5f74dd5132da7d0321377aAndy Huang window.scrollBy(deltaScrollX, deltaScrollY); 7224c54e3627861351c6c5f74dd5132da7d0321377aAndy Huang }, 10); 72302f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang} 72402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 72502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huangfunction onScale(relativeScale, screenX, screenY) { 72602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var scale; 72702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var translateX, translateY; 72802f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang var transform; 72902f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 73002f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang if (!gScaleInfo) { 73102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang return; 73202f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang } 73302f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 73402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang scale = Math.max(gScaleInfo.initialScale * relativeScale, gScaleInfo.minScale); 73502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang if (scale > 4.0) { 73602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang scale = 4.0; 73702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang } 738ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang translateX = screenX - gScaleInfo.initialScreenX; 739ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang translateY = screenY - gScaleInfo.initialScreenY; 740ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang // TODO: clamp translation to prevent going beyond body edges 74102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang gScaleInfo.currScale = scale; 742ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang gScaleInfo.currTranslateX = translateX; 743ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang gScaleInfo.currTranslateY = translateY; 74402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang transform = "translate3d(" + translateX + "px," + translateY + "px,0) scale3d(" 74502f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang + scale + "," + scale + ",1) translate3d(" + gScaleInfo.translateX + "px," 74602f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang + gScaleInfo.translateY + "px,0)"; 74702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang gScaleInfo.div.style.webkitTransform = transform; 748ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang// console.log("JS got scale=" + scale + " x/y=" + screenX + "/" + screenY 74902f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang// + " transform='" + transform + "'"); 75002f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang} 75102f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 7523233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang// END Java->JavaScript handlers 7533233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang 7544cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang// Do this first to ensure that the readiness signal comes through, 7554cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang// even if a stray exception later occurs. 7564cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy HuangsetupContentReady(); 7574cfe22a8b0fe9fb98df9c82303bacc5c1a79f19bAndy Huang 758014ea4c15d147794789b9c5bf4e243fa08781ad9Andy HuangcollapseAllQuotedText(); 759f500db85dd13394dd6bdcfa38824b2ca6ada77e8Andy HuanghideAllUnsafeImages(); 760ffc725fe4b4fa1024feb22b1d1f76c24febadcdbAndy HuangnormalizeAllMessageWidths(); 76123014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang//setWideViewport(); 762e964eeec3a088b3f4c29b68d41f99e43a321ac52Andy HuangrestoreScrollPosition(); 763f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy HuangmeasurePositions(); 764f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 765