// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Common js for prerender loaders; defines the helper functions that put // event handlers on prerenders and track the events for browser tests. // TODO(gavinp): Put more common loader logic in here. // Currently only errors with the ordering of Prerender events are caught. var hadPrerenderEventErrors = false; var receivedPrerenderEvents = { 'webkitprerenderstart': [], 'webkitprerenderdomcontentloaded': [], 'webkitprerenderload': [], 'webkitprerenderstop': [], } // A list of callbacks to be called on every prerender event. Each callback // returns true if it should never be called again, or false to remain in the // list and be called on future events. These are used to implement // WaitForPrerenderEventCount. var prerenderEventCallbacks = []; function GetPrerenderEventCount(index, type) { return receivedPrerenderEvents[type][index] || 0; } function PrerenderEventHandler(index, ev) { // Check for errors. if (ev.type == 'webkitprerenderstart') { // No event may preceed start. if (GetPrerenderEventCount(index, 'webkitprerenderstart') || GetPrerenderEventCount(index, 'webkitprerenderdomcontentloaded') || GetPrerenderEventCount(index, 'webkitprerenderload') || GetPrerenderEventCount(index, 'webkitprerenderstop')) { hadPrerenderEventErrors = true; } } else { // There may be multiple load or domcontentloaded events, but they must not // come after start and must come before stop. And there may be at most one // start. Note that stop may be delivered without any load events. if (!GetPrerenderEventCount(index, 'webkitprerenderstart') || GetPrerenderEventCount(index, 'webkitprerenderstop')) { hadPrerenderEventErrors = true; } } // Update count. receivedPrerenderEvents[ev.type][index] = (receivedPrerenderEvents[ev.type][index] || 0) + 1; // Run all callbacks. Remove the ones that are done. prerenderEventCallbacks = prerenderEventCallbacks.filter(function(callback) { return !callback(); }); } // Calls |callback| when at least |count| instances of event |type| have been // observed for prerender |index|. function WaitForPrerenderEventCount(index, type, count, callback) { var checkCount = function() { if (GetPrerenderEventCount(index, type) >= count) { callback(); return true; } return false; }; if (!checkCount()) prerenderEventCallbacks.push(checkCount); } function AddEventHandlersToLinkElement(link, index) { link.addEventListener('webkitprerenderstart', PrerenderEventHandler.bind(null, index), false); link.addEventListener('webkitprerenderdomcontentloaded', PrerenderEventHandler.bind(null, index), false); link.addEventListener('webkitprerenderload', PrerenderEventHandler.bind(null, index), false); link.addEventListener('webkitprerenderstop', PrerenderEventHandler.bind(null, index), false); } function AddPrerender(url, index) { var link = document.createElement('link'); link.id = 'prerenderElement' + index; link.rel = 'prerender'; link.href = url; AddEventHandlersToLinkElement(link, index); document.body.appendChild(link); return link; } function RemoveLinkElement(index) { var link = document.getElementById('prerenderElement' + index); link.parentElement.removeChild(link); } function ExtractGetParameterBadlyAndInsecurely(param, defaultValue) { var re = RegExp('[&?]' + param + '=([^&?#]*)'); var result = re.exec(document.location); if (result) return result[1]; return defaultValue; } function AddAnchor(href, target) { var a = document.createElement('a'); a.href = href; if (target) a.target = target; document.body.appendChild(a); return a; } function Click(url) { AddAnchor(url).dispatchEvent(new MouseEvent('click', { view: window, bubbles: true, cancelable: true, detail: 1 })); } function ClickTarget(url) { var eventObject = new MouseEvent('click', { view: window, bubbles: true, cancelable: true, detail: 1 }); AddAnchor(url, '_blank').dispatchEvent(eventObject); } function ClickPing(url, pingUrl) { var a = AddAnchor(url); a.ping = pingUrl; a.dispatchEvent(new MouseEvent('click', { view: window, bubbles: true, cancelable: true, detail: 1 })); } function ShiftClick(url) { AddAnchor(url).dispatchEvent(new MouseEvent('click', { view: window, bubbles: true, cancelable: true, detail: 1, shiftKey: true })); } function CtrlClick(url) { AddAnchor(url).dispatchEvent(new MouseEvent('click', { view: window, bubbles: true, cancelable: true, detail: 1, ctrlKey: true })); } function CtrlShiftClick(url) { AddAnchor(url).dispatchEvent(new MouseEvent('click', { view: window, bubbles: true, cancelable: true, detail: 1, ctrlKey: true, shiftKey: true })); } function MetaClick(url) { AddAnchor(url).dispatchEvent(new MouseEvent('click', { view: window, bubbles: true, cancelable: true, detail: 1, metaKey: true })); } function MetaShiftClick(url) { AddAnchor(url).dispatchEvent(new MouseEvent('click', { view: window, bubbles: true, cancelable: true, detail: 1, metaKey: true, shiftKey: true })); } function WindowOpen(url) { window.open(url); }