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 button to dismiss an item.
66 * @param {Function} func Callback called when the button is clicked.
68 function createDismissingButton(func
) {
69 var button
= document
.createElement('button');
70 button
.textContent
= 'X';
71 button
.classList
.add('dismissing');
72 button
.addEventListener('click', function(e
) {
80 * Creates a new LI element with a button to dismiss the item.
82 * @param {string} text The lable of the LI element.
83 * @param {Function} func Callback called when the button is clicked.
85 function createLIWithDismissingButton(text
, func
) {
86 var span
= document
.createElement('span');
87 span
.textContent
= text
;
89 var li
= document
.createElement('li');
91 li
.appendChild(createDismissingButton(func
));
96 * Formats the language name to a human-readable text. For example, if
97 * |langCode| is 'en', this may return 'en (English)'.
99 * @param {string} langCode ISO 639 language code.
100 * @return {string} The formatted string.
102 function formatLanguageCode(langCode
) {
103 var key
= 'language-' + langCode
;
104 if (loadTimeData
.valueExists(key
)) {
105 var langName
= loadTimeData
.getString(key
);
106 return langCode
+ ' (' + langName
+ ')';
113 * Formats the error type to a human-readable text.
115 * @param {string} error Translation error type from the browser.
116 * @return {string} The formatted string.
118 function formatTranslateErrorsType(error
) {
119 // This list is from chrome/common/translate/translate_errors.h.
120 // If this header file is updated, the below list also should be updated.
124 2: 'Initialization Error',
125 3: 'Unknown Language',
126 4: 'Unsupported Language',
127 5: 'Identical Languages',
128 6: 'Translation Error',
129 7: 'Translation Timeout',
130 8: 'Unexpected Script Error',
132 10: 'Script Load Error',
135 if (error
< 0 || errorStrs
.length
<= error
) {
136 console
.error('Invalid error code:', error
);
137 return 'Invalid Error Code';
139 return errorStrs
[error
];
143 * Handles the message of 'prefsUpdated' from the browser.
145 * @param {Object} detail the object which represents pref values.
147 function onPrefsUpdated(detail
) {
150 ul
= document
.querySelector('#prefs-blocked-languages ul');
153 if ('translate_blocked_languages' in detail
) {
154 var langs
= detail
['translate_blocked_languages'];
156 langs
.forEach(function(langCode
) {
157 var text
= formatLanguageCode(langCode
);
159 var li
= createLIWithDismissingButton(text
, function() {
160 chrome
.send('removePrefItem',
161 ['blocked_languages', langCode
]);
167 ul
= document
.querySelector('#prefs-language-blacklist ul');
170 if ('translate_language_blacklist' in detail
) {
171 var langs
= detail
['translate_language_blacklist'];
173 langs
.forEach(function(langCode
) {
174 var text
= formatLanguageCode(langCode
);
176 var li
= createLIWithDismissingButton(text
, function() {
177 chrome
.send('removePrefItem',
178 ['language_blacklist', langCode
]);
184 ul
= document
.querySelector('#prefs-site-blacklist ul');
187 if ('translate_site_blacklist' in detail
) {
188 var sites
= detail
['translate_site_blacklist'];
190 sites
.forEach(function(site
) {
191 var li
= createLIWithDismissingButton(site
, function() {
192 chrome
.send('removePrefItem', ['site_blacklist', site
]);
198 ul
= document
.querySelector('#prefs-whitelists ul');
201 if ('translate_whitelists' in detail
) {
202 var pairs
= detail
['translate_whitelists'];
204 Object
.keys(pairs
).forEach(function(fromLangCode
) {
205 var toLangCode
= pairs
[fromLangCode
];
206 var text
= formatLanguageCode(fromLangCode
) + ' \u2192 ' +
207 formatLanguageCode(toLangCode
);
209 var li
= createLIWithDismissingButton(text
, function() {
210 chrome
.send('removePrefItem',
211 ['whitelists', fromLangCode
, toLangCode
]);
217 var p
= $('prefs-too-often-denied');
218 p
.classList
.toggle('prefs-setting-disabled',
219 !detail
['translate_too_often_denied']);
220 p
.appendChild(createDismissingButton(
221 chrome
.send
.bind(null, 'removePrefItem', ['too_often_denied'])));
223 p
= document
.querySelector('#prefs-dump p');
224 var content
= JSON
.stringify(detail
, null, 2);
225 p
.textContent
= content
;
229 * Handles the message of 'supportedLanguagesUpdated' from the browser.
231 * @param {Object} details the object which represents the supported
232 * languages by the Translate server.
234 function onSupportedLanguagesUpdated(details
) {
236 $('prefs-supported-languages-last-updated').querySelector('span');
237 span
.textContent
= formatDate(new Date(details
['last_updated']));
239 var ul
= $('prefs-supported-languages-languages');
241 var languages
= details
['languages'];
242 for (var i
= 0; i
< languages
.length
; i
++) {
243 var language
= languages
[i
];
244 var li
= document
.createElement('li');
246 var text
= formatLanguageCode(language
);
247 if (details
['alpha_languages'].indexOf(language
) != -1)
256 * Addes '0's to |number| as a string. |width| is length of the string
259 * @param {string} number The number to be converted into a string.
260 * @param {number} width The width of the returned string.
261 * @return {string} The formatted string.
263 function padWithZeros(number
, width
) {
264 var numberStr
= number
.toString();
265 var restWidth
= width
- numberStr
.length
;
269 return Array(restWidth
+ 1).join('0') + numberStr
;
273 * Formats |date| as a Date object into a string. The format is like
274 * '2006-01-02 15:04:05'.
276 * @param {Date} date Date to be formatted.
277 * @return {string} The formatted string.
279 function formatDate(date
) {
280 var year
= date
.getFullYear();
281 var month
= date
.getMonth() + 1;
282 var day
= date
.getDate();
283 var hour
= date
.getHours();
284 var minute
= date
.getMinutes();
285 var second
= date
.getSeconds();
287 var yearStr
= padWithZeros(year
, 4);
288 var monthStr
= padWithZeros(month
, 2);
289 var dayStr
= padWithZeros(day
, 2);
290 var hourStr
= padWithZeros(hour
, 2);
291 var minuteStr
= padWithZeros(minute
, 2);
292 var secondStr
= padWithZeros(second
, 2);
294 var str
= yearStr
+ '-' + monthStr
+ '-' + dayStr
+ ' ' +
295 hourStr
+ ':' + minuteStr
+ ':' + secondStr
;
301 * Appends a new TD element to the specified element.
303 * @param {string} parent The element to which a new TD element is appended.
304 * @param {string} content The text content of the element.
305 * @param {string} className The class name of the element.
307 function appendTD(parent
, content
, className
) {
308 var td
= document
.createElement('td');
309 td
.textContent
= content
;
310 td
.className
= className
;
311 parent
.appendChild(td
);
315 * Handles the message of 'languageDetectionInfoAdded' from the
318 * @param {Object} detail The object which represents the logs.
320 function onLanguageDetectionInfoAdded(detail
) {
321 cr
.translateInternals
.detectionLogs().push(detail
);
323 var tr
= document
.createElement('tr');
325 appendTD(tr
, formatDate(new Date(detail
['time'])), 'detection-logs-time');
326 appendTD(tr
, detail
['url'], 'detection-logs-url');
327 appendTD(tr
, formatLanguageCode(detail
['content_language']),
328 'detection-logs-content-language');
329 appendTD(tr
, formatLanguageCode(detail
['cld_language']),
330 'detection-logs-cld-language');
331 appendTD(tr
, detail
['is_cld_reliable'], 'detection-logs-is-cld-reliable');
332 appendTD(tr
, detail
['has_notranslate'], 'detection-logs-has-notranslate');
333 appendTD(tr
, formatLanguageCode(detail
['html_root_language']),
334 'detection-logs-html-root-language');
335 appendTD(tr
, formatLanguageCode(detail
['adopted_language']),
336 'detection-logs-adopted-language');
337 appendTD(tr
, formatLanguageCode(detail
['content']),
338 'detection-logs-content');
340 // TD (and TR) can't use the CSS property 'max-height', so DIV
341 // in the content is needed.
342 var contentTD
= tr
.querySelector('.detection-logs-content');
343 var div
= document
.createElement('div');
344 div
.textContent
= contentTD
.textContent
;
345 contentTD
.textContent
= '';
346 contentTD
.appendChild(div
);
348 var tabpanel
= $('tabpanel-detection-logs');
349 var tbody
= tabpanel
.getElementsByTagName('tbody')[0];
350 tbody
.appendChild(tr
);
354 * Handles the message of 'translateErrorDetailsAdded' from the
357 * @param {Object} details The object which represents the logs.
359 function onTranslateErrorDetailsAdded(details
) {
360 var tr
= document
.createElement('tr');
362 appendTD(tr
, formatDate(new Date(details
['time'])), 'error-logs-time');
363 appendTD(tr
, details
['url'], 'error-logs-url');
366 details
['error'] + ': ' + formatTranslateErrorsType(details
['error']),
369 var tabpanel
= $('tabpanel-error-logs');
370 var tbody
= tabpanel
.getElementsByTagName('tbody')[0];
371 tbody
.appendChild(tr
);
375 * Handles the message of 'translateEventDetailsAdded' from the browser.
377 * @param {Object} details The object which contains event information.
379 function onTranslateEventDetailsAdded(details
) {
380 var tr
= document
.createElement('tr');
381 appendTD(tr
, formatDate(new Date(details
['time'])), 'event-logs-time');
382 appendTD(tr
, details
['filename'] + ': ' + details
['line'],
384 appendTD(tr
, details
['message'], 'event-logs-message');
386 var tbody
= $('tabpanel-event-logs').getElementsByTagName('tbody')[0];
387 tbody
.appendChild(tr
);
391 * The callback entry point from the browser. This function will be
392 * called by the browser.
394 * @param {string} message The name of the sent message.
395 * @param {Object} details The argument of the sent message.
397 function messageHandler(message
, details
) {
399 case 'languageDetectionInfoAdded':
400 onLanguageDetectionInfoAdded(details
);
403 onPrefsUpdated(details
);
405 case 'supportedLanguagesUpdated':
406 onSupportedLanguagesUpdated(details
);
408 case 'translateErrorDetailsAdded':
409 onTranslateErrorDetailsAdded(details
);
411 case 'translateEventDetailsAdded':
412 onTranslateEventDetailsAdded(details
);
415 console
.error('Unknown message:', message
);
421 * The callback of button#detetion-logs-dump.
423 function onDetectionLogsDump() {
424 var data
= JSON
.stringify(cr
.translateInternals
.detectionLogs());
425 var blob
= new Blob([data
], {'type': 'text/json'});
426 var url
= URL
.createObjectURL(blob
);
427 var filename
= 'translate_internals_detect_logs_dump.json';
429 var a
= document
.createElement('a');
430 a
.setAttribute('href', url
);
431 a
.setAttribute('download', filename
);
433 var event
= document
.createEvent('MouseEvent');
434 event
.initMouseEvent('click', true, true, window
, 0,
435 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
436 a
.dispatchEvent(event
);
440 detectionLogs
: detectionLogs
,
441 initialize
: initialize
,
442 messageHandler
: messageHandler
,
447 * The entry point of the UI.
450 cr
.doc
.addEventListener('DOMContentLoaded',
451 cr
.translateInternals
.initialize
);