// Copyright 2013 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. (function() { 'use strict'; cr.define('cr.translateInternals', function() { var detectionLogs_ = null; function detectionLogs() { if (detectionLogs_ === null) detectionLogs_ = []; return detectionLogs_; } /** * Initializes UI and sends a message to the browser for * initialization. */ function initialize() { cr.ui.decorate('tabbox', cr.ui.TabBox); chrome.send('requestInfo'); var button = $('detection-logs-dump'); button.addEventListener('click', onDetectionLogsDump); var enableTranslateSettings = templateData['enable-translate-settings']; if (!enableTranslateSettings) { $('prefs-blocked-languages').hidden = true; $('prefs-language-blacklist').querySelector('h2 span').hidden = true; } } /** * Creates a new LI element with a button to dismiss the item. * * @param {string} text The lable of the LI element. * @param {Function} func Callback called when the button is clicked. */ function createLIWithDismissingButton(text, func) { var span = document.createElement('span'); span.textContent = text; var li = document.createElement('li'); li.appendChild(span); var button = document.createElement('button'); button.textContent = 'X'; button.addEventListener('click', function(e) { e.preventDefault(); func(); }, false); li.appendChild(button); return li; } /** * Formats the language name to a human-readable text. For example, if * |langCode| is 'en', this may return 'en (English)'. * * @param {string} langCode ISO 639 language code. * @return {string} The formatted string. */ function formatLanguageCode(langCode) { var key = 'language-' + langCode; if (key in templateData) { var langName = templateData[key]; return langCode + ' (' + langName + ')'; } return langCode; } /** * Formats the error type to a human-readable text. * * @param {string} error Translation error type from the browser. * @return {string} The formatted string. */ function formatTranslateErrorsType(error) { // This list is from chrome/common/translate/translate_errors.h. // If this header file is updated, the below list also should be updated. var errorStrs = { 0: 'None', 1: 'Network', 2: 'Initialization Error', 3: 'Unknown Language', 4: 'Unsupported Language', 5: 'Identical Languages', 6: 'Translation Error', }; if (error < 0 || errorStrs.length <= error) { console.error('Invalid error code:', error); return 'Invalid Error Code'; } return errorStrs[error]; } /** * Handles the message of 'prefsUpdated' from the browser. * * @param {Object} detail the object which represents pref values. */ function onPrefsUpdated(detail) { var ul; ul = document.querySelector('#prefs-blocked-languages ul'); ul.innerHTML = ''; if ('translate_blocked_languages' in detail) { var langs = detail['translate_blocked_languages']; langs.forEach(function(langCode) { var text = formatLanguageCode(langCode); var li = createLIWithDismissingButton(text, function() { chrome.send('removePrefItem', ['blocked_languages', langCode]); }); ul.appendChild(li); }); } ul = document.querySelector('#prefs-language-blacklist ul'); ul.innerHTML = ''; if ('translate_language_blacklist' in detail) { var langs = detail['translate_language_blacklist']; langs.forEach(function(langCode) { var text = formatLanguageCode(langCode); var li = createLIWithDismissingButton(text, function() { chrome.send('removePrefItem', ['language_blacklist', langCode]); }); ul.appendChild(li); }); } ul = document.querySelector('#prefs-site-blacklist ul'); ul.innerHTML = ''; if ('translate_site_blacklist' in detail) { var sites = detail['translate_site_blacklist']; sites.forEach(function(site) { var li = createLIWithDismissingButton(site, function() { chrome.send('removePrefItem', ['site_blacklist', site]); }); ul.appendChild(li); }); } ul = document.querySelector('#prefs-whitelists ul'); ul.innerHTML = ''; if ('translate_whitelists' in detail) { var pairs = detail['translate_whitelists']; Object.keys(pairs).forEach(function(fromLangCode) { var toLangCode = pairs[fromLangCode]; var text = formatLanguageCode(fromLangCode) + ' \u2192 ' + formatLanguageCode(toLangCode); var li = createLIWithDismissingButton(text, function() { chrome.send('removePrefItem', ['whitelists', fromLangCode, toLangCode]); }); ul.appendChild(li); }); } var p = document.querySelector('#prefs-dump p'); var content = JSON.stringify(detail, null, 2); p.textContent = content; } /** * Handles the message of 'supportedLanguagesUpdated' from the browser. * * @param {Object} details the object which represents the supported * languages by the Translate server. */ function onSupportedLanguagesUpdated(details) { var span = $('prefs-supported-languages-last-updated').querySelector('span'); span.textContent = formatDate(new Date(details['last_updated'])); var ul = $('prefs-supported-languages-languages'); ul.innerHTML = ''; var languages = details['languages']; for (var i = 0; i < languages.length; i++) { var language = languages[i]; var li = document.createElement('li'); var text = formatLanguageCode(language); if (details['alpha_languages'].indexOf(language) != -1) text += ' - alpha'; li.innerText = text; ul.appendChild(li); } } /** * Addes '0's to |number| as a string. |width| is length of the string * including '0's. * * @param {string} number The number to be converted into a string. * @param {number} width The width of the returned string. * @return {string} The formatted string. */ function padWithZeros(number, width) { var numberStr = number.toString(); var restWidth = width - numberStr.length; if (restWidth <= 0) return numberStr; return Array(restWidth + 1).join('0') + numberStr; } /** * Formats |date| as a Date object into a string. The format is like * '2006-01-02 15:04:05'. * * @param {Date} date Date to be formatted. * @return {string} The formatted string. */ function formatDate(date) { var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDay(); var hour = date.getHours(); var minute = date.getMinutes(); var second = date.getSeconds(); var yearStr = padWithZeros(year, 4); var monthStr = padWithZeros(month, 2); var dayStr = padWithZeros(day, 2); var hourStr = padWithZeros(hour, 2); var minuteStr = padWithZeros(minute, 2); var secondStr = padWithZeros(second, 2); var str = yearStr + '-' + monthStr + '-' + dayStr + ' ' + hourStr + ':' + minuteStr + ':' + secondStr; return str; } /** * Appends a new TD element to the specified element. * * @param {string} parent The element to which a new TD element is appended. * @param {string} content The text content of the element. * @param {string} className The class name of the element. */ function appendTD(parent, content, className) { var td = document.createElement('td'); td.textContent = content; td.className = className; parent.appendChild(td); } /** * Handles the message of 'languageDetectionInfoAdded' from the * browser. * * @param {Object} detail The object which represents the logs. */ function onLanguageDetectionInfoAdded(detail) { cr.translateInternals.detectionLogs().push(detail); var tr = document.createElement('tr'); appendTD(tr, formatDate(new Date(detail['time'])), 'detection-logs-time'); appendTD(tr, detail['url'], 'detection-logs-url'); appendTD(tr, formatLanguageCode(detail['content_language']), 'detection-logs-content-language'); appendTD(tr, formatLanguageCode(detail['cld_language']), 'detection-logs-cld-language'); appendTD(tr, detail['is_cld_reliable'], 'detection-logs-is-cld-reliable'); appendTD(tr, formatLanguageCode(detail['html_root_language']), 'detection-logs-html-root-language'); appendTD(tr, formatLanguageCode(detail['adopted_language']), 'detection-logs-adopted-language'); appendTD(tr, formatLanguageCode(detail['content']), 'detection-logs-content'); // TD (and TR) can't use the CSS property 'max-height', so DIV // in the content is needed. var contentTD = tr.querySelector('.detection-logs-content'); var div = document.createElement('div'); div.textContent = contentTD.textContent; contentTD.textContent = ''; contentTD.appendChild(div); var tbody = $('detection-logs').getElementsByTagName('tbody')[0]; tbody.appendChild(tr); } /** * Handles the message of 'translateErrorDetailsAdded' from the * browser. * * @param {Object} details The object which represents the logs. */ function onTranslateErrorDetailsAdded(details) { var tr = document.createElement('tr'); appendTD(tr, formatDate(new Date(details['time'])), 'error-logs-time'); appendTD(tr, details['url'], 'error-logs-url'); appendTD( tr, details['error'] + ': ' + formatTranslateErrorsType(details['error']), 'error-logs-error'); var tbody = $('error-logs').getElementsByTagName('tbody')[0]; tbody.appendChild(tr); } /** * Handles the message of 'translateEventDetailsAdded' from the browser. * * @param {Object} details The object which contains event information. */ function onTranslateEventDetailsAdded(details) { var tr = document.createElement('tr'); appendTD(tr, formatDate(new Date(details['time'])), 'event-logs-time'); appendTD(tr, details['filename'] + ': ' + details['line'], 'event-logs-place'); appendTD(tr, details['message'], 'event-logs-message'); var tbody = $('event-logs').getElementsByTagName('tbody')[0]; tbody.appendChild(tr); } /** * The callback entry point from the browser. This function will be * called by the browser. * * @param {string} message The name of the sent message. * @param {Object} details The argument of the sent message. */ function messageHandler(message, details) { switch (message) { case 'languageDetectionInfoAdded': onLanguageDetectionInfoAdded(details); break; case 'prefsUpdated': onPrefsUpdated(details); break; case 'supportedLanguagesUpdated': onSupportedLanguagesUpdated(details); break; case 'translateErrorDetailsAdded': onTranslateErrorDetailsAdded(details); break; case 'translateEventDetailsAdded': onTranslateEventDetailsAdded(details); break; default: console.error('Unknown message:', message); break; } } /** * The callback of button#detetion-logs-dump. */ function onDetectionLogsDump() { var data = JSON.stringify(cr.translateInternals.detectionLogs()); var blob = new Blob([data], {'type': 'text/json'}); var url = webkitURL.createObjectURL(blob); var filename = 'translate_internals_detect_logs_dump.json'; var a = document.createElement('a'); a.setAttribute('href', url); a.setAttribute('download', filename); var event = document.createEvent('MouseEvent'); event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null); a.dispatchEvent(event); } return { detectionLogs: detectionLogs, initialize: initialize, messageHandler: messageHandler, }; }); /** * The entry point of the UI. */ function main() { cr.doc.addEventListener('DOMContentLoaded', cr.translateInternals.initialize); } main(); })();