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) 5effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochcr.define('chrome.sync.about_tab', function() { 6effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Contains the latest snapshot of sync about info. 7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chrome.sync.aboutInfo = {}; 8effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 9c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch function highlightIfChanged(node, oldVal, newVal) { 10c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch function clearHighlight() { 11c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch this.removeAttribute('highlighted'); 12c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch var oldStr = oldVal.toString(); 15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch var newStr = newVal.toString(); 16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (oldStr != '' && oldStr != newStr) { 17c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Note the addListener function does not end up creating duplicate 18c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // listeners. There can be only one listener per event at a time. 19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Reference: https://developer.mozilla.org/en/DOM/element.addEventListener 20c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch node.addEventListener('webkitAnimationEnd', clearHighlight, false); 21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch node.setAttribute('highlighted', ''); 22c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch function refreshAboutInfo(aboutInfo) { 26effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chrome.sync.aboutInfo = aboutInfo; 27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var aboutInfoDiv = $('about-info'); 28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch jstProcess(new JsEvalContext(aboutInfo), aboutInfoDiv); 29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch function onAboutInfoUpdatedEvent(e) { 32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch refreshAboutInfo(e.details); 33effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch /** 360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Helper to determine if an element is scrolled to its bottom limit. 370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * @param {Element} elem element to check 380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * @return {boolean} true if the element is scrolled to the bottom 390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch */ 400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch function isScrolledToBottom(elem) { 410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return elem.scrollHeight - elem.scrollTop == elem.clientHeight; 420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch /** 450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Helper to scroll an element to its bottom limit. 460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * @param {Element} elem element to be scrolled 470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch */ 480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch function scrollToBottom(elem) { 490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch elem.scrollTop = elem.scrollHeight - elem.clientHeight; 500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 52effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** Container for accumulated sync protocol events. */ 53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var protocolEvents = []; 54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 55e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch /** We may receive re-delivered events. Keep a record of ones we've seen. */ 56e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch var knownEventTimestamps = {}; 57e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** 59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Callback for incoming protocol events. 60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * @param {Event} e The protocol event. 61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch function onReceivedProtocolEvent(e) { 63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var details = e.details; 64e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 65e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Return early if we've seen this event before. Assumes that timestamps 66e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // are sufficiently high resolution to uniquely identify an event. 67e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (knownEventTimestamps.hasOwnProperty(details.time)) { 68e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return; 69e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 70e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 71e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch knownEventTimestamps[details.time] = true; 72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch protocolEvents.push(details); 73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch var trafficContainer = $('traffic-event-container'); 750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // Scroll to the bottom if we were already at the bottom. Otherwise, leave 770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // the scrollbar alone. 780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch var shouldScrollDown = isScrolledToBottom(trafficContainer); 790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var context = new JsEvalContext({ events: protocolEvents }); 810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch jstProcess(context, trafficContainer); 820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (shouldScrollDown) 840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch scrollToBottom(trafficContainer); 85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** 88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Initializes state and callbacks for the protocol event log UI. 89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch function initProtocolEventLog() { 91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chrome.sync.events.addEventListener( 92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 'onProtocolEvent', onReceivedProtocolEvent); 93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Make the prototype jscontent element disappear. 95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch jstProcess({}, $('traffic-event-container')); 96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** 99e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch * Initializes listeners for status dump and import UI. 100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 101e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch function initStatusDumpButton() { 102effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch $('status-data').hidden = true; 103effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var dumpStatusButton = $('dump-status'); 105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch dumpStatusButton.addEventListener('click', function(event) { 106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var aboutInfo = chrome.sync.aboutInfo; 107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!$('include-ids').checked) { 108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch aboutInfo.details = chrome.sync.aboutInfo.details.filter(function(el) { 109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return !el.is_sensitive; 110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch }); 111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var data = ''; 113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch data += new Date().toString() + '\n'; 114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch data += '======\n'; 115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch data += 'Status\n'; 116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch data += '======\n'; 117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch data += JSON.stringify(aboutInfo, null, 2) + '\n'; 118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch $('status-text').value = data; 120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch $('status-data').hidden = false; 121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch }); 122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var importStatusButton = $('import-status'); 124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch importStatusButton.addEventListener('click', function(event) { 125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch $('status-data').hidden = false; 126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if ($('status-text').value.length == 0) { 127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch $('status-text').value = 128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 'Paste sync status dump here then click import.'; 129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // First remove any characters before the '{'. 133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var data = $('status-text').value; 134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var firstBrace = data.indexOf('{'); 135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (firstBrace < 0) { 136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch $('status-text').value = 'Invalid sync status dump.'; 137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch data = data.substr(firstBrace); 140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Remove listeners to prevent sync events from overwriting imported data. 142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chrome.sync.events.removeEventListener( 143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 'onAboutInfoUpdated', 144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch onAboutInfoUpdatedEvent); 145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var aboutInfo = JSON.parse(data); 147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch refreshAboutInfo(aboutInfo); 148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch }); 149e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 151e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch /** 152e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch * Toggles the given traffic event entry div's "expanded" state. 1530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * @param {MouseEvent} e the click event that triggered the toggle. 154e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch */ 1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch function expandListener(e) { 1560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch e.target.classList.toggle('traffic-event-entry-expanded'); 157e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 158e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 159e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch /** 160e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch * Attaches a listener to the given traffic event entry div. 161e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch * @param {HTMLElement} element the element to attach the listener to. 162e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch */ 163e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch function addExpandListener(element) { 164e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch element.addEventListener('click', expandListener, false); 165e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 166e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 167e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch function onLoad() { 168e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch initStatusDumpButton(); 169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch initProtocolEventLog(); 170e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 171e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch chrome.sync.events.addEventListener( 172e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 'onAboutInfoUpdated', 173e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch onAboutInfoUpdatedEvent); 174e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 175e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Register to receive a stream of event notifications. 176e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch chrome.sync.registerForEvents(); 177e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 178e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Request an about info update event to initialize the page. 179e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch chrome.sync.requestUpdatedAboutInfo(); 180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return { 183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch onLoad: onLoad, 184c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch addExpandListener: addExpandListener, 185c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch highlightIfChanged: highlightIfChanged 186effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch }; 187effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochdocument.addEventListener( 190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 'DOMContentLoaded', chrome.sync.about_tab.onLoad, false); 191