| 'use strict'; |
| |
| // Concept heavily borrowed from |
| // //depot/google3/wireless/android/tools/android_bug_tool/extension/listnr_content_script/listnr_content_script.ts |
| |
| // WARNING: This function may not reference any non-globals outside this |
| // function as it is stringified below to be inserted into the page. |
| function setup() { |
| if (typeof angular !== 'undefined') { |
| angular.element(document.documentElement)['injector']().invoke( |
| ($rootScope) => { |
| $rootScope.$on('$locationChangeSuccess', (e) => { |
| window.postMessage( |
| {source: '__shill_log_tool', message: 'LOCATION_UPDATED'}, |
| '*'); |
| }); |
| $rootScope.$watch(() => { |
| window.postMessage( |
| {source: '__shill_log_tool', message: 'DIGEST'}, '*'); |
| }); |
| }); |
| } |
| } |
| |
| const INJECTED_ANGULAR_UPDATE_DETECTION_SCRIPT = |
| '(' + setup.toString() + ')();'; |
| |
| // Inject script into Listnr page. |
| const script = document.createElement('script'); |
| script.textContent = INJECTED_ANGULAR_UPDATE_DETECTION_SCRIPT; |
| document.head.appendChild(script); |
| |
| // Setup listener for events angular update events from Listnr page. |
| window.addEventListener('message', (e) => { |
| if (e.data.source === '__shill_log_tool') { |
| if (e.data.message === 'LOCATION_UPDATED' || e.data.message === 'DIGEST') { |
| delayedUpdate(); |
| } |
| } |
| }); |
| |
| const UPDATE_DEBOUNCE_DELAY = 500; |
| let pendingTimer = null; |
| /** |
| * Schedule a delayed update. If an update is already scheduled then it is |
| * canceled and replaced with the new timer. |
| */ |
| function delayedUpdate() { |
| if (pendingTimer) { |
| clearTimeout(pendingTimer); |
| pendingTimer = null; |
| } |
| pendingTimer = window.setTimeout(() => { |
| pendingTimer = null; |
| update(); |
| }, UPDATE_DEBOUNCE_DELAY); |
| } |
| |
| function forEachUnprocessedAttachmentSectionsMarkAnd(callback) { |
| const attachmentSections = document.body.querySelectorAll( |
| '[section-title="Product Specific Binary Data"] > div.zipper > ng-transclude'); |
| for (let i = 0; i < attachmentSections.length; ++i) { |
| const attachmentsSection = |
| attachmentSections[i]; |
| if (attachmentsSection.__shill_log_tool) { |
| continue; |
| } |
| attachmentsSection.__shill_log_tool = true; |
| callback(attachmentsSection); |
| } |
| } |
| |
| function createAttachmentLinkWithLoading( |
| text, addedClass, target) { |
| const link = document.createElement('a'); |
| link.classList.add(addedClass); |
| link.style.cursor = 'pointer'; |
| link.style.marginLeft = '1em'; |
| link.onclick = (ev) => { |
| // Change the link to a loading stage. |
| link.style.pointerEvents = 'none'; |
| if (link.lastChild == null) { |
| throw new Error('No element found in link'); |
| } else { |
| link.lastChild.textContent = ' Opening...'; |
| } |
| |
| // Perform the action. |
| target(ev); |
| }; |
| link.appendChild(document.createTextNode(' ' + text)); |
| return link; |
| } |
| |
| function removeLoadingState(element, originalText, addedClass) { |
| const link = element.querySelector('.' + addedClass); |
| if (!link) return; |
| link.style.pointerEvents = 'auto'; |
| if (link.lastChild != null) { |
| link.lastChild.textContent = originalText; |
| } |
| } |
| |
| function createOpenShillToolLink(downloadUrl, attachment) { |
| const className = 'open-shill-tool-link'; |
| const magnifyingGlassEmoji = '\u{1F50D}'; |
| const humanName = magnifyingGlassEmoji + ' Open Shill Log Tool'; |
| |
| return createAttachmentLinkWithLoading( |
| humanName, className, () => { |
| chrome.runtime.sendMessage( |
| {'action': 'open_shill_page', 'data': downloadUrl}, () => { |
| console.log('got fix link callback'); |
| removeLoadingState( |
| attachment, humanName, className); |
| }); |
| }); |
| } |
| |
| function getDownloadUrlFromAttachmentElement(attachment) { |
| const existingLinks = attachment.querySelectorAll('a'); |
| for (let i = 0; i < existingLinks.length; ++i) { |
| const existingLink = existingLinks[i]; |
| if (existingLink.textContent && |
| existingLink.textContent.trim() === 'file_download') { |
| return existingLink.href; |
| } |
| } |
| return null; |
| } |
| |
| function update() { |
| forEachUnprocessedAttachmentSectionsMarkAnd((attachmentsSection) => { |
| const attachments = attachmentsSection.querySelectorAll('div > div'); |
| const downloadUrls = []; |
| |
| for (let i = 0; i < attachments.length; ++i) { |
| const attachment = attachments[i]; |
| const downloadUrl = getDownloadUrlFromAttachmentElement(attachment); |
| |
| if (downloadUrl) { |
| if (downloadUrl.includes('system_logs.zip')) { |
| attachment.appendChild( |
| createOpenShillToolLink(downloadUrl, attachment)); |
| } |
| } |
| } |
| }); |
| } |
| |
| delayedUpdate(); |