15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cr.define('uber', function() { 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Options for how web history should be handled. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var HISTORY_STATE_OPTION = { 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PUSH: 1, // Push a new history state. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) REPLACE: 2, // Replace the current history state. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NONE: 3, // Ignore this history state change. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * We cache a reference to the #navigation frame here so we don't need to grab 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * it from the DOM on each scroll. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type {Node} 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var navFrame; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Handles page initialization. 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function onLoad(e) { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame = $('navigation'); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.dataset.width = navFrame.offsetWidth; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Select a page based on the page-URL. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var params = resolvePageInfo(); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) showPage(params.id, HISTORY_STATE_OPTION.NONE, params.path); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window.addEventListener('message', handleWindowMessage); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window.setTimeout(function() { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) document.documentElement.classList.remove('loading'); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, 0); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HACK(dbeam): This makes the assumption that any second part to a path 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will result in needing background navigation. We shortcut it to avoid 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // flicker on load. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HACK(csilv): Search URLs aren't overlays, special case them. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (params.id == 'settings' && params.path && 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.path.indexOf('search') != 0) { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) backgroundNavigation(); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 47a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ensureNonSelectedFrameContainersAreHidden(); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Find page information from window.location. If the location doesn't 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * point to one of our pages, return default parameters. 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Object} An object containing the following parameters: 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * id - The 'id' of the page. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * path - A path into the page, including search and hash. Optional. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function resolvePageInfo() { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var params = {}; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var path = window.location.pathname; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path.length > 1) { 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Split the path into id and the remaining path. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = path.slice(1); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var index = path.indexOf('/'); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index != -1) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.id = path.slice(0, index); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.path = path.slice(index + 1); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.id = path; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var container = $(params.id); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (container) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The id is valid. Add the hash and search parts of the URL to path. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.path = (params.path || '') + window.location.search + 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window.location.hash; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The target sub-page does not exist, discard the params we generated. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.id = undefined; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.path = undefined; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we don't have a valid page, get a default. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!params.id) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.id = getDefaultIframe().id; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return params; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Handler for window.onpopstate. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Event} e The history event. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function onPopHistoryState(e) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (e.state && e.state.pageId) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) showPage(e.state.pageId, HISTORY_STATE_OPTION.NONE); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Object} The default iframe container. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function getDefaultIframe() { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return $(loadTimeData.getString('helpHost')); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Object} The currently selected iframe container. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function getSelectedIframe() { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return document.querySelector('.iframe-container.selected'); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Handles postMessage calls from the iframes of the contained pages. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The pages request functionality from this object by passing an object of 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the following form: 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * { method : "methodToInvoke", 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * params : {...} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * } 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * |method| is required, while |params| is optional. Extra parameters required 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * by a method must be specified by that method's documentation. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Event} e The posted object. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function handleWindowMessage(e) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (e.data.method === 'beginInterceptingEvents') 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) backgroundNavigation(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (e.data.method === 'stopInterceptingEvents') 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) foregroundNavigation(); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (e.data.method === 'setPath') 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setPath(e.origin, e.data.params.path); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (e.data.method === 'setTitle') 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setTitle(e.origin, e.data.params.title); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (e.data.method === 'showPage') 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) showPage(e.data.params.pageId, HISTORY_STATE_OPTION.PUSH); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (e.data.method === 'navigationControlsLoaded') 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) onNavigationControlsLoaded(); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (e.data.method === 'adjustToScroll') 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) adjustToScroll(e.data.params); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (e.data.method === 'mouseWheel') 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) forwardMouseWheel(e.data.params); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) console.error('Received unexpected message', e.data); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Sends the navigation iframe to the background. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function backgroundNavigation() { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.classList.add('background'); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.firstChild.tabIndex = -1; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.firstChild.setAttribute('aria-hidden', true); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Retrieves the navigation iframe from the background. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function foregroundNavigation() { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.classList.remove('background'); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.firstChild.tabIndex = 0; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.firstChild.removeAttribute('aria-hidden'); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Enables or disables animated transitions when changing content while 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * horizontally scrolled. 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {boolean} enabled True if enabled, else false to disable. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function setContentChanging(enabled) { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.classList[enabled ? 'add' : 'remove']('changing-content'); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (isRTL()) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uber.invokeMethodOnWindow(navFrame.firstChild.contentWindow, 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'setContentChanging', 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enabled); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Get an iframe based on the origin of a received post message. 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} origin The origin of a post message. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {!HTMLElement} The frame associated to |origin| or null. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function getIframeFromOrigin(origin) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(origin.substr(-1) != '/', 'invalid origin given'); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var query = '.iframe-container > iframe[src^="' + origin + '/"]'; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return document.querySelector(query); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Changes the path past the page title (i.e. chrome://chrome/settings/(.*)). 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} path The new /path/ to be set after the page name. 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} historyOption The type of history modification to make. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function changePathTo(path, historyOption) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(!path || path.substr(-1) != '/', 'invalid path given'); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var histFunc; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (historyOption == HISTORY_STATE_OPTION.PUSH) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histFunc = window.history.pushState; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (historyOption == HISTORY_STATE_OPTION.REPLACE) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histFunc = window.history.replaceState; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(histFunc, 'invalid historyOption given ' + historyOption); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var pageId = getSelectedIframe().id; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var args = [{pageId: pageId}, '', '/' + pageId + '/' + (path || '')]; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histFunc.apply(window.history, args); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Sets the "path" of the page (actually the path after the first '/' char). 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} origin The origin of the source iframe. 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} title The new "path". 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function setPath(origin, path) { 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(!path || path[0] != '/', 'invalid path sent from ' + origin); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only update the currently displayed path if this is the visible frame. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (getIframeFromOrigin(origin).parentNode == getSelectedIframe()) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) changePathTo(path, HISTORY_STATE_OPTION.REPLACE); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Sets the title of the page. 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} origin The origin of the source iframe. 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} title The title of the page. 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function setTitle(origin, title) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cache the title for the client iframe, i.e., the iframe setting the 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // title. querySelector returns the actual iframe element, so use parentNode 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to get back to the container. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var container = getIframeFromOrigin(origin).parentNode; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container.dataset.title = title; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only update the currently displayed title if this is the visible frame. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (container == getSelectedIframe()) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) document.title = title; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Selects a subpage. This is called from uber-frame. 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {string} pageId Should matche an id of one of the iframe containers. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {integer} historyOption Indicates whether we should push or replace 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * browser history. 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {string} path A sub-page path. 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function showPage(pageId, historyOption, path) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var container = $(pageId); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var lastSelected = document.querySelector('.iframe-container.selected'); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Lazy load of iframe contents. 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var sourceUrl = container.dataset.url + (path || ''); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var frame = container.querySelector('iframe'); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!frame) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame = container.ownerDocument.createElement('iframe'); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container.appendChild(frame); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame.src = sourceUrl; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There's no particularly good way to know what the current URL of the 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // content frame is as we don't have access to its contentWindow's 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // location, so just replace every time until necessary to do otherwise. 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame.contentWindow.location.replace(sourceUrl); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the last selected container is already showing, ignore the rest. 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lastSelected === container) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 272a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (lastSelected) { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lastSelected.classList.remove('selected'); 274a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Setting aria-hidden hides the container from assistive technology 275a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // immediately. The 'hidden' attribute is set after the transition 276a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // finishes - that ensures it's not possible to accidentally focus 277a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // an element in an unselected container. 278a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) lastSelected.setAttribute('aria-hidden', 'true'); 279a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 280a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Containers that aren't selected have to be hidden so that their 282a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // content isn't focusable. 283a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) container.hidden = false; 284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) container.setAttribute('aria-hidden', 'false'); 285a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 286a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Trigger a layout after making it visible and before setting 287a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // the class to 'selected', so that it animates in. 288a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) container.offsetTop; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) container.classList.add('selected'); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setContentChanging(true); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) adjustToScroll(0); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var selectedFrame = getSelectedIframe().querySelector('iframe'); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uber.invokeMethodOnWindow(selectedFrame.contentWindow, 'frameSelected'); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (historyOption != HISTORY_STATE_OPTION.NONE) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) changePathTo(path, historyOption); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (container.dataset.title) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) document.title = container.dataset.title; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $('favicon').href = 'chrome://theme/' + container.dataset.favicon; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $('favicon2x').href = 'chrome://theme/' + container.dataset.favicon + '@2x'; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) updateNavigationControls(); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function onNavigationControlsLoaded() { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) updateNavigationControls(); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Sends a message to uber-frame to update the appearance of the nav controls. 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * It should be called whenever the selected iframe changes. 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function updateNavigationControls() { 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var iframe = getSelectedIframe(); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uber.invokeMethodOnWindow(navFrame.firstChild.contentWindow, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'changeSelection', {pageId: iframe.id}); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Forwarded scroll offset from a content frame's scroll handler. 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} scrollOffset The scroll offset from the content frame. 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function adjustToScroll(scrollOffset) { 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: The scroll is reset to 0 and easing turned on every time a user 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // switches frames. If we receive a non-zero value it has to have come from 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a real user scroll, so we disable easing when this happens. 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scrollOffset != 0) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setContentChanging(false); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (isRTL()) { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uber.invokeMethodOnWindow(navFrame.firstChild.contentWindow, 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'adjustToScroll', 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scrollOffset); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var navWidth = Math.max(0, +navFrame.dataset.width + scrollOffset); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.style.width = navWidth + 'px'; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) navFrame.style.webkitTransform = 'translateX(' + -scrollOffset + 'px)'; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Forward scroll wheel events to subpages. 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} params Relevant parameters of wheel event. 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function forwardMouseWheel(params) { 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var iframe = getSelectedIframe().querySelector('iframe'); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uber.invokeMethodOnWindow(iframe.contentWindow, 'mouseWheel', params); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 353a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) /** 354a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * Make sure that iframe containers that are not selected are 355a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * hidden, so that elements in those frames aren't part of the 356a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * focus order. Containers that are unselected later get hidden 357a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * when the transition ends. We also set the aria-hidden attribute 358a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * because that hides the container from assistive technology 359a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * immediately, rather than only after the transition ends. 360a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) */ 361a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) function ensureNonSelectedFrameContainersAreHidden() { 362a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) var containers = document.querySelectorAll('.iframe-container'); 363a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) for (var i = 0; i < containers.length; i++) { 364a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) var container = containers[i]; 365a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!container.classList.contains('selected')) { 366a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) container.hidden = true; 367a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) container.setAttribute('aria-hidden', 'true'); 368a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 369a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) container.addEventListener('webkitTransitionEnd', function(event) { 370a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!event.target.classList.contains('selected')) 371a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) event.target.hidden = true; 372a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) }); 373a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 374a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 375a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) onLoad: onLoad, 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) onPopHistoryState: onPopHistoryState 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)window.addEventListener('popstate', uber.onPopHistoryState); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)document.addEventListener('DOMContentLoaded', uber.onLoad); 384