Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / resources / translate_internals / translate_internals.js
blobe6ecc1b8b984172f0b66982f227ad3367533c7f6
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.
5 (function() {
6   'use strict';
8   cr.define('cr.translateInternals', function() {
10     var detectionLogs_ = null;
12     function detectionLogs() {
13       if (detectionLogs_ === null)
14         detectionLogs_ = [];
15       return detectionLogs_;
16     }
18     /**
19      * Initializes UI and sends a message to the browser for
20      * initialization.
21      */
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) {
32         return tab.id;
33       });
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;
43         };
44       });
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)
54           return;
56         $(id).selected = true;
57       };
59       window.onhashchange = activateTabByHash;
60       activateTabByHash();
61     }
63     /*
64      * Creates a button to dismiss an item.
65      *
66      * @param {Function} func Callback called when the button is clicked.
67      */
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) {
73         e.preventDefault();
74         func();
75       }, false);
76       return button;
77     }
79     /**
80      * Creates a new LI element with a button to dismiss the item.
81      *
82      * @param {string} text The lable of the LI element.
83      * @param {Function} func Callback called when the button is clicked.
84      */
85     function createLIWithDismissingButton(text, func) {
86       var span = document.createElement('span');
87       span.textContent = text;
89       var li = document.createElement('li');
90       li.appendChild(span);
91       li.appendChild(createDismissingButton(func));
92       return li;
93     }
95     /**
96      * Formats the language name to a human-readable text. For example, if
97      * |langCode| is 'en', this may return 'en (English)'.
98      *
99      * @param {string} langCode ISO 639 language code.
100      * @return {string} The formatted string.
101      */
102     function formatLanguageCode(langCode) {
103       var key = 'language-' + langCode;
104       if (loadTimeData.valueExists(key)) {
105         var langName = loadTimeData.getString(key);
106         return langCode + ' (' + langName + ')';
107       }
109       return langCode;
110     }
112     /**
113      * Formats the error type to a human-readable text.
114      *
115      * @param {string} error Translation error type from the browser.
116      * @return {string} The formatted string.
117      */
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.
121       var errorStrs = {
122         0: 'None',
123         1: 'Network',
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',
131         9: 'Bad Origin',
132         10: 'Script Load Error',
133       };
135       if (error < 0 || errorStrs.length <= error) {
136         console.error('Invalid error code:', error);
137         return 'Invalid Error Code';
138       }
139       return errorStrs[error];
140     }
142     /**
143      * Handles the message of 'prefsUpdated' from the browser.
144      *
145      * @param {Object} detail the object which represents pref values.
146      */
147     function onPrefsUpdated(detail) {
148       var ul;
150       ul = document.querySelector('#prefs-blocked-languages ul');
151       ul.innerHTML = '';
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]);
162           });
163           ul.appendChild(li);
164         });
165       }
167       ul = document.querySelector('#prefs-language-blacklist ul');
168       ul.innerHTML = '';
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]);
179           });
180           ul.appendChild(li);
181         });
182       }
184       ul = document.querySelector('#prefs-site-blacklist ul');
185       ul.innerHTML = '';
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]);
193           });
194           ul.appendChild(li);
195         });
196       }
198       ul = document.querySelector('#prefs-whitelists ul');
199       ul.innerHTML = '';
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]);
212           });
213           ul.appendChild(li);
214         });
215       }
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;
226     }
228     /**
229      * Handles the message of 'supportedLanguagesUpdated' from the browser.
230      *
231      * @param {Object} details the object which represents the supported
232      *     languages by the Translate server.
233      */
234     function onSupportedLanguagesUpdated(details) {
235       var span =
236           $('prefs-supported-languages-last-updated').querySelector('span');
237       span.textContent = formatDate(new Date(details['last_updated']));
239       var ul = $('prefs-supported-languages-languages');
240       ul.innerHTML = '';
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)
248           text += ' - alpha';
249         li.innerText = text;
251         ul.appendChild(li);
252       }
253     }
255     /**
256      * Addes '0's to |number| as a string. |width| is length of the string
257      * including '0's.
258      *
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.
262      */
263     function padWithZeros(number, width) {
264       var numberStr = number.toString();
265       var restWidth = width - numberStr.length;
266       if (restWidth <= 0)
267         return numberStr;
269       return Array(restWidth + 1).join('0') + numberStr;
270     }
272     /**
273      * Formats |date| as a Date object into a string. The format is like
274      * '2006-01-02 15:04:05'.
275      *
276      * @param {Date} date Date to be formatted.
277      * @return {string} The formatted string.
278      */
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;
297       return str;
298     }
300     /**
301      * Appends a new TD element to the specified element.
302      *
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.
306      */
307     function appendTD(parent, content, className) {
308       var td = document.createElement('td');
309       td.textContent = content;
310       td.className = className;
311       parent.appendChild(td);
312     }
314     /**
315      * Handles the message of 'languageDetectionInfoAdded' from the
316      * browser.
317      *
318      * @param {Object} detail The object which represents the logs.
319      */
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);
351     }
353     /**
354      * Handles the message of 'translateErrorDetailsAdded' from the
355      * browser.
356      *
357      * @param {Object} details The object which represents the logs.
358      */
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');
364       appendTD(
365           tr,
366           details['error'] + ': ' + formatTranslateErrorsType(details['error']),
367           'error-logs-error');
369       var tabpanel = $('tabpanel-error-logs');
370       var tbody = tabpanel.getElementsByTagName('tbody')[0];
371       tbody.appendChild(tr);
372     }
374     /**
375      * Handles the message of 'translateEventDetailsAdded' from the browser.
376      *
377      * @param {Object} details The object which contains event information.
378      */
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'],
383                'event-logs-place');
384       appendTD(tr, details['message'], 'event-logs-message');
386       var tbody = $('tabpanel-event-logs').getElementsByTagName('tbody')[0];
387       tbody.appendChild(tr);
388     }
390     /**
391      * The callback entry point from the browser. This function will be
392      * called by the browser.
393      *
394      * @param {string} message The name of the sent message.
395      * @param {Object} details The argument of the sent message.
396      */
397     function messageHandler(message, details) {
398       switch (message) {
399         case 'languageDetectionInfoAdded':
400           onLanguageDetectionInfoAdded(details);
401           break;
402         case 'prefsUpdated':
403           onPrefsUpdated(details);
404           break;
405         case 'supportedLanguagesUpdated':
406           onSupportedLanguagesUpdated(details);
407           break;
408         case 'translateErrorDetailsAdded':
409           onTranslateErrorDetailsAdded(details);
410           break;
411         case 'translateEventDetailsAdded':
412           onTranslateEventDetailsAdded(details);
413           break;
414         default:
415           console.error('Unknown message:', message);
416           break;
417       }
418     }
420     /**
421      * The callback of button#detetion-logs-dump.
422      */
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);
437     }
439     return {
440       detectionLogs: detectionLogs,
441       initialize: initialize,
442       messageHandler: messageHandler,
443     };
444   });
446   /**
447    * The entry point of the UI.
448    */
449   function main() {
450     cr.doc.addEventListener('DOMContentLoaded',
451                             cr.translateInternals.initialize);
452   }
454   main();
455 })();