1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 cr.define('cr.translateInternals', function() {
10 var detectionLogs_ = null;
12 function detectionLogs() {
13 if (detectionLogs_ === null)
15 return detectionLogs_;
19 * Initializes UI and sends a message to the browser for
22 function initialize() {
23 cr.ui.decorate('tabbox', cr.ui.TabBox);
24 chrome.send('requestInfo');
26 var button = $('detection-logs-dump');
27 button.addEventListener('click', onDetectionLogsDump);
29 var tabpanelNodeList = document.getElementsByTagName('tabpanel');
30 var tabpanels = Array.prototype.slice.call(tabpanelNodeList, 0);
31 var tabpanelIds = tabpanels.map(function(tab) {
35 var tabNodeList = document.getElementsByTagName('tab');
36 var tabs = Array.prototype.slice.call(tabNodeList, 0);
37 tabs.forEach(function(tab) {
38 tab.onclick = function(e) {
39 var tabbox = document.querySelector('tabbox');
40 var tabpanel = tabpanels[tabbox.selectedIndex];
41 var hash = tabpanel.id.match(/(?:^tabpanel-)(.+)/)[1];
42 window.location.hash = hash;
46 var activateTabByHash = function() {
47 var hash = window.location.hash;
49 // Remove the first character '#'.
50 hash = hash.substring(1);
52 var id = 'tabpanel-' + hash;
53 if (tabpanelIds.indexOf(id) == -1)
56 $(id).selected = true;
59 window.onhashchange = activateTabByHash;
64 * Creates a new LI element with a button to dismiss the item.
66 * @param {string} text The lable of the LI element.
67 * @param {Function} func Callback called when the button is clicked.
69 function createLIWithDismissingButton(text, func) {
70 var span = document.createElement('span');
71 span.textContent = text;
73 var li = document.createElement('li');
76 var button = document.createElement('button');
77 button.textContent = 'X';
78 button.addEventListener('click', function(e) {
83 li.appendChild(button);
88 * Formats the language name to a human-readable text. For example, if
89 * |langCode| is 'en', this may return 'en (English)'.
91 * @param {string} langCode ISO 639 language code.
92 * @return {string} The formatted string.
94 function formatLanguageCode(langCode) {
95 var key = 'language-' + langCode;
96 if (key in templateData) {
97 var langName = templateData[key];
98 return langCode + ' (' + langName + ')';
105 * Formats the error type to a human-readable text.
107 * @param {string} error Translation error type from the browser.
108 * @return {string} The formatted string.
110 function formatTranslateErrorsType(error) {
111 // This list is from chrome/common/translate/translate_errors.h.
112 // If this header file is updated, the below list also should be updated.
116 2: 'Initialization Error',
117 3: 'Unknown Language',
118 4: 'Unsupported Language',
119 5: 'Identical Languages',
120 6: 'Translation Error',
121 7: 'Translation Timeout',
122 8: 'Unexpected Script Error',
124 10: 'Script Load Error',
127 if (error < 0 || errorStrs.length <= error) {
128 console.error('Invalid error code:', error);
129 return 'Invalid Error Code';
131 return errorStrs[error];
135 * Handles the message of 'prefsUpdated' from the browser.
137 * @param {Object} detail the object which represents pref values.
139 function onPrefsUpdated(detail) {
142 ul = document.querySelector('#prefs-blocked-languages ul');
145 if ('translate_blocked_languages' in detail) {
146 var langs = detail['translate_blocked_languages'];
148 langs.forEach(function(langCode) {
149 var text = formatLanguageCode(langCode);
151 var li = createLIWithDismissingButton(text, function() {
152 chrome.send('removePrefItem',
153 ['blocked_languages', langCode]);
159 ul = document.querySelector('#prefs-language-blacklist ul');
162 if ('translate_language_blacklist' in detail) {
163 var langs = detail['translate_language_blacklist'];
165 langs.forEach(function(langCode) {
166 var text = formatLanguageCode(langCode);
168 var li = createLIWithDismissingButton(text, function() {
169 chrome.send('removePrefItem',
170 ['language_blacklist', langCode]);
176 ul = document.querySelector('#prefs-site-blacklist ul');
179 if ('translate_site_blacklist' in detail) {
180 var sites = detail['translate_site_blacklist'];
182 sites.forEach(function(site) {
183 var li = createLIWithDismissingButton(site, function() {
184 chrome.send('removePrefItem', ['site_blacklist', site]);
190 ul = document.querySelector('#prefs-whitelists ul');
193 if ('translate_whitelists' in detail) {
194 var pairs = detail['translate_whitelists'];
196 Object.keys(pairs).forEach(function(fromLangCode) {
197 var toLangCode = pairs[fromLangCode];
198 var text = formatLanguageCode(fromLangCode) + ' \u2192 ' +
199 formatLanguageCode(toLangCode);
201 var li = createLIWithDismissingButton(text, function() {
202 chrome.send('removePrefItem',
203 ['whitelists', fromLangCode, toLangCode]);
209 var p = document.querySelector('#prefs-dump p');
210 var content = JSON.stringify(detail, null, 2);
211 p.textContent = content;
215 * Handles the message of 'supportedLanguagesUpdated' from the browser.
217 * @param {Object} details the object which represents the supported
218 * languages by the Translate server.
220 function onSupportedLanguagesUpdated(details) {
222 $('prefs-supported-languages-last-updated').querySelector('span');
223 span.textContent = formatDate(new Date(details['last_updated']));
225 var ul = $('prefs-supported-languages-languages');
227 var languages = details['languages'];
228 for (var i = 0; i < languages.length; i++) {
229 var language = languages[i];
230 var li = document.createElement('li');
232 var text = formatLanguageCode(language);
233 if (details['alpha_languages'].indexOf(language) != -1)
242 * Addes '0's to |number| as a string. |width| is length of the string
245 * @param {string} number The number to be converted into a string.
246 * @param {number} width The width of the returned string.
247 * @return {string} The formatted string.
249 function padWithZeros(number, width) {
250 var numberStr = number.toString();
251 var restWidth = width - numberStr.length;
255 return Array(restWidth + 1).join('0') + numberStr;
259 * Formats |date| as a Date object into a string. The format is like
260 * '2006-01-02 15:04:05'.
262 * @param {Date} date Date to be formatted.
263 * @return {string} The formatted string.
265 function formatDate(date) {
266 var year = date.getFullYear();
267 var month = date.getMonth() + 1;
268 var day = date.getDate();
269 var hour = date.getHours();
270 var minute = date.getMinutes();
271 var second = date.getSeconds();
273 var yearStr = padWithZeros(year, 4);
274 var monthStr = padWithZeros(month, 2);
275 var dayStr = padWithZeros(day, 2);
276 var hourStr = padWithZeros(hour, 2);
277 var minuteStr = padWithZeros(minute, 2);
278 var secondStr = padWithZeros(second, 2);
280 var str = yearStr + '-' + monthStr + '-' + dayStr + ' ' +
281 hourStr + ':' + minuteStr + ':' + secondStr;
287 * Appends a new TD element to the specified element.
289 * @param {string} parent The element to which a new TD element is appended.
290 * @param {string} content The text content of the element.
291 * @param {string} className The class name of the element.
293 function appendTD(parent, content, className) {
294 var td = document.createElement('td');
295 td.textContent = content;
296 td.className = className;
297 parent.appendChild(td);
301 * Handles the message of 'languageDetectionInfoAdded' from the
304 * @param {Object} detail The object which represents the logs.
306 function onLanguageDetectionInfoAdded(detail) {
307 cr.translateInternals.detectionLogs().push(detail);
309 var tr = document.createElement('tr');
311 appendTD(tr, formatDate(new Date(detail['time'])), 'detection-logs-time');
312 appendTD(tr, detail['url'], 'detection-logs-url');
313 appendTD(tr, formatLanguageCode(detail['content_language']),
314 'detection-logs-content-language');
315 appendTD(tr, formatLanguageCode(detail['cld_language']),
316 'detection-logs-cld-language');
317 appendTD(tr, detail['is_cld_reliable'], 'detection-logs-is-cld-reliable');
318 appendTD(tr, formatLanguageCode(detail['html_root_language']),
319 'detection-logs-html-root-language');
320 appendTD(tr, formatLanguageCode(detail['adopted_language']),
321 'detection-logs-adopted-language');
322 appendTD(tr, formatLanguageCode(detail['content']),
323 'detection-logs-content');
325 // TD (and TR) can't use the CSS property 'max-height', so DIV
326 // in the content is needed.
327 var contentTD = tr.querySelector('.detection-logs-content');
328 var div = document.createElement('div');
329 div.textContent = contentTD.textContent;
330 contentTD.textContent = '';
331 contentTD.appendChild(div);
333 var tabpanel = $('tabpanel-detection-logs');
334 var tbody = tabpanel.getElementsByTagName('tbody')[0];
335 tbody.appendChild(tr);
339 * Handles the message of 'translateErrorDetailsAdded' from the
342 * @param {Object} details The object which represents the logs.
344 function onTranslateErrorDetailsAdded(details) {
345 var tr = document.createElement('tr');
347 appendTD(tr, formatDate(new Date(details['time'])), 'error-logs-time');
348 appendTD(tr, details['url'], 'error-logs-url');
351 details['error'] + ': ' + formatTranslateErrorsType(details['error']),
354 var tabpanel = $('tabpanel-error-logs');
355 var tbody = tabpanel.getElementsByTagName('tbody')[0];
356 tbody.appendChild(tr);
360 * Handles the message of 'translateEventDetailsAdded' from the browser.
362 * @param {Object} details The object which contains event information.
364 function onTranslateEventDetailsAdded(details) {
365 var tr = document.createElement('tr');
366 appendTD(tr, formatDate(new Date(details['time'])), 'event-logs-time');
367 appendTD(tr, details['filename'] + ': ' + details['line'],
369 appendTD(tr, details['message'], 'event-logs-message');
371 var tbody = $('event-logs').getElementsByTagName('tbody')[0];
372 tbody.appendChild(tr);
376 * The callback entry point from the browser. This function will be
377 * called by the browser.
379 * @param {string} message The name of the sent message.
380 * @param {Object} details The argument of the sent message.
382 function messageHandler(message, details) {
384 case 'languageDetectionInfoAdded':
385 onLanguageDetectionInfoAdded(details);
388 onPrefsUpdated(details);
390 case 'supportedLanguagesUpdated':
391 onSupportedLanguagesUpdated(details);
393 case 'translateErrorDetailsAdded':
394 onTranslateErrorDetailsAdded(details);
396 case 'translateEventDetailsAdded':
397 onTranslateEventDetailsAdded(details);
400 console.error('Unknown message:', message);
406 * The callback of button#detetion-logs-dump.
408 function onDetectionLogsDump() {
409 var data = JSON.stringify(cr.translateInternals.detectionLogs());
410 var blob = new Blob([data], {'type': 'text/json'});
411 var url = URL.createObjectURL(blob);
412 var filename = 'translate_internals_detect_logs_dump.json';
414 var a = document.createElement('a');
415 a.setAttribute('href', url);
416 a.setAttribute('download', filename);
418 var event = document.createEvent('MouseEvent');
419 event.initMouseEvent('click', true, true, window, 0,
420 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
421 a.dispatchEvent(event);
425 detectionLogs: detectionLogs,
426 initialize: initialize,
427 messageHandler: messageHandler,
432 * The entry point of the UI.
435 cr.doc.addEventListener('DOMContentLoaded',
436 cr.translateInternals.initialize);