(function($) {
'use strict';
const HOME_PAGE = 'home';
const PACKAGE_RESULTS_PAGE = 'packages.php';
const DETAILS_PAGE = 'details.php';
const REVIEW_PAGE = 'review.php';
const BOOK_PAGE = 'confirm.php';
const HOTEL_ONLY_RESULTS_PAGE = 'hotels.php';
const HOME_PAGE_SELECTOR = '.at-tp-submit:contains(Search)'; // search button
const PACKAGE_RESULTS_PAGE_SELECTOR = '.result .js-fb-track.btn-bookit:contains(Select Hotel)'; // select hotel button
const HOTEL_ONLY_RESULTS_PAGE_SELECTOR = '.result .js-fb-track.btn-bookit:contains(Select Hotel)'; // select hotel button
const DETAILS_PAGE_SELECTOR = '.room .select-button.at-details-select:contains(Select)'; // select room button
const REVIEW_PAGE_SELECTOR = '#trip-summary .continue-btn:contains(CONTINUE)'; // continue to book button
const BOOK_PAGE_SELECTOR = '.agree-terms-container .continue-btn:contains(BOOK IT)'; // book button
const HOME_PAGE_PAGE_FLIGHT_SELECTOR = '.trip-select:contains(Flight) > span.icon-checkbox'; // flight package check box
const PAGE_SELECTORS = [
HOME_PAGE_SELECTOR,
PACKAGE_RESULTS_PAGE_SELECTOR,
HOTEL_ONLY_RESULTS_PAGE_SELECTOR,
DETAILS_PAGE_SELECTOR,
REVIEW_PAGE_SELECTOR,
BOOK_PAGE_SELECTOR
];
var elementWatchTimer;
/**
* Poll the DOM for an element and call a callback with the time it was found
*
* @param {string} selector
* @param {function} callback
*/
function waitForElement(selector, callback) {
elementWatchTimer = setInterval(function(){
if ($(selector).length > 0) {
clearInterval(elementWatchTimer);
callback(moment());
}
}, 100);
}
/**
* Get the Selector whose presence on the page indicates that the given page is loaded
*
* @param {string} page The name of the page
* @return {string}
*/
function getSelectorForPage(page) {
var selector;
switch (page) {
case HOME_PAGE:
selector = HOME_PAGE_SELECTOR;
break;
case PACKAGE_RESULTS_PAGE:
selector = PACKAGE_RESULTS_PAGE_SELECTOR;
break;
case HOTEL_ONLY_RESULTS_PAGE:
selector = HOTEL_ONLY_RESULTS_PAGE_SELECTOR;
break;
case DETAILS_PAGE:
selector = DETAILS_PAGE_SELECTOR;
break;
case REVIEW_PAGE:
selector = REVIEW_PAGE_SELECTOR;
break;
case BOOK_PAGE:
selector = BOOK_PAGE_SELECTOR;
break;
}
return selector;
}
/**
* Get time it took to load in seconds with precision
*
* @param startedAt
* @param loadedAt
*/
function getLoadTime(startedAt, loadedAt) {
var duration = moment.duration(loadedAt.diff(startedAt));
return ((duration.asMilliseconds() % 10000) / 1000).toFixed(2);
}
/**
* Set the time the page was "fully loaded"
* ie, ready to click the button to go to the next page
*
* @param page
* @param loadedTime
*/
function setLoadTimeForPage(page, loadedTime) {
var timeTest = getTimeTest();
timeTest[page].loadedAt= loadedTime;
timeTest[page].loadTime = getLoadTime(timeTest[page].startedAt, loadedTime);
setLocal('timeTest', timeTest);
}
/**
* Get a value from our storage
* like localStorage but shared across subdomains
*
* @param key
*/
function getLocal(key) {
return GM_getValue(key);
}
/**
* Set a value to our storage
* like localStorage but shared across subdomains
*
* @param key
* @param data
*/
function setLocal(key,data) {
GM_setValue(key, data);
}
/**
* Set the start loading time for the current page but
* only if if wasn't already set elsewhere
*
* @param page
* @param startTime
*/
function setStartTimeForPage(page, startTime) {
var timeTest = getTimeTest();
if (!timeTest[page]) {
timeTest[page] = {};
}
// set time when page started to load, if it wasnt already set elsewhere
var message = 'Time test initiated on previous page...';
if (!timeTest[page].startedAt) {
message = 'Initiating time test';
timeTest[page].startedAt = startTime;
setLocal('timeTest', timeTest);
}
logTimeTestStage(message);
}
/**
* Get the current time test data from storage
*/
function getTimeTest() {
return getLocal('timeTest') || {};
}
/**
* Log a table to the console displaying all the time test data
*/
function displayResultsTable() {
var timeTest = getTimeTest();
var displayData = [];
var elapsedTime = 0;
$.each(timeTest,function (page, data) {
var row = {};
row['Page Name'] = page;
row['Load Start'] = moment(data.startedAt).tz('America/New_York').format('ddd, MMM Do YYYY, h:mm:ss a z');
row['Load Finish'] = moment(data.loadedAt).tz('America/New_York').format('ddd, MMM Do YYYY, h:mm:ss a z');
row['Load Time'] = data.loadTime + ' seconds';
elapsedTime = elapsedTime + parseFloat(data.loadTime);
displayData.push(row);
});
var row = {};
row['Page Name'] = 'Total All Pages';
row['Load Start'] = '-';
row['Load Finish'] = '-';
row['Load Time'] = elapsedTime.toFixed(2)+' seconds';
displayData.push(row);
console.table(displayData);
}
/**
* Get the current page file name
* @return {string}
*/
function getPage() {
var path = window.location.pathname;
return path === '/' ? HOME_PAGE : path.split("/").pop();
}
/**
* Returns true if the current search is a package search, on the homepage
* @return {boolean}
*/
function isPackageSearch() {
return $(HOME_PAGE_PAGE_FLIGHT_SELECTOR).length > 0;
}
/**
* Log some info to the console to show each stage of the time test
*
* @param {string} message Message stating what stage we are logging
*/
function logTimeTestStage(message) {
console.log('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
console.log(message+'----------------------------------------------------------------------------------------------------------------------------------------------------------');
console.log(getTimeTest());
console.log('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
console.warn('*** Tables only print if the console is open. Use window.reprocessTimeTestTable() to reprocess the table of data, in case the console was closed when the page was loaded. ***');
console.log('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
}
/**
* Get the next page in the progression of the funnel after the given page
* @param currentPage
* @return {string}
*/
function getNextPage(currentPage) {
var nextPage;
switch (currentPage) {
case HOME_PAGE:
// if the flight box is checked it the TP, package results is next
if (isPackageSearch()) {
nextPage = PACKAGE_RESULTS_PAGE;
} else {
nextPage = HOTEL_ONLY_RESULTS_PAGE;
}
break;
case HOTEL_ONLY_RESULTS_PAGE:
case PACKAGE_RESULTS_PAGE:
nextPage = DETAILS_PAGE;
break;
case DETAILS_PAGE:
nextPage = REVIEW_PAGE;
break;
case REVIEW_PAGE:
nextPage = BOOK_PAGE;
break;
}
return nextPage;
}
/**
* Start logging page time data
*/
function beginLoggingPageTimeTestInfo() {
var page = getPage();
var selector = getSelectorForPage(page);
if (page === HOME_PAGE) {
// if this is the home page, reset our metrics
setLocal('timeTest', null);
}
setStartTimeForPage(page, moment());;
// wait for the page to be fully "loaded", ie, we can move to the next page
waitForElement(selector, function(loadedTime){
setLoadTimeForPage(page, loadedTime);
logTimeTestStage('Finished time test');
displayResultsTable();
});
}
/**
* When user clicks the search button on homepage
* start the timer for the results page
*/
var pageButtonSelectors = PAGE_SELECTORS.join(', ');
var userClickedButton = true;
$(document).on('mousedown', pageButtonSelectors, function (e) {
// when the user clicks the button
// stop the navigation event so we can log the start time
if (userClickedButton) {
e.preventDefault();
userClickedButton = false;
logTimeTestStage('Initiating time test for next page');
var nextPage = getNextPage(getPage());
setStartTimeForPage(nextPage, moment());
// now re-click the button
var $this=$(this);
$this.click();
}
});
// set this on the main window so users can display the table if the console
// was closed when it ran originally since they cant access it directly
unsafeWindow.reprocessTimeTestTable = displayResultsTable;
// debugger; // un-comment for easier debugging
// setLocal('timeTest',null); // un-comment to clear data for testing
beginLoggingPageTimeTestInfo(); // kick off the logging
})(jQuery);