OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // The scripts supported by the Font Settings Extension API. | 5 'use strict'; |
6 var scripts = [ | 6 |
7 { scriptCode: 'Zyyy', scriptName: 'Default'}, | 7 /** |
8 * @fileoverview The Advanced Font Settings Extension implementation. | |
9 */ | |
10 | |
11 function $(id) { | |
12 return document.getElementById(id); | |
13 } | |
14 | |
15 /** | |
16 * @namespace | |
17 */ | |
18 var advancedFonts = {}; | |
19 | |
20 /** | |
21 * The ICU script code for the Common, or global, script, which is used as the | |
22 * fallback when the script is undeclared. | |
23 * @const | |
24 */ | |
25 advancedFonts.COMMON_SCRIPT = 'Zyyy'; | |
26 | |
27 /** | |
28 * The scripts supported by the Font Settings Extension API. | |
29 * @const | |
30 */ | |
31 advancedFonts.scripts = [ | |
32 { scriptCode: advancedFonts.COMMON_SCRIPT, scriptName: 'Default'}, | |
8 { scriptCode: 'Afak', scriptName: 'Afaka'}, | 33 { scriptCode: 'Afak', scriptName: 'Afaka'}, |
9 { scriptCode: 'Arab', scriptName: 'Arabic'}, | 34 { scriptCode: 'Arab', scriptName: 'Arabic'}, |
10 { scriptCode: 'Armi', scriptName: 'Imperial Aramaic'}, | 35 { scriptCode: 'Armi', scriptName: 'Imperial Aramaic'}, |
11 { scriptCode: 'Armn', scriptName: 'Armenian'}, | 36 { scriptCode: 'Armn', scriptName: 'Armenian'}, |
12 { scriptCode: 'Avst', scriptName: 'Avestan'}, | 37 { scriptCode: 'Avst', scriptName: 'Avestan'}, |
13 { scriptCode: 'Bali', scriptName: 'Balinese'}, | 38 { scriptCode: 'Bali', scriptName: 'Balinese'}, |
14 { scriptCode: 'Bamu', scriptName: 'Bamum'}, | 39 { scriptCode: 'Bamu', scriptName: 'Bamum'}, |
15 { scriptCode: 'Bass', scriptName: 'Bassa Vah'}, | 40 { scriptCode: 'Bass', scriptName: 'Bassa Vah'}, |
16 { scriptCode: 'Batk', scriptName: 'Batak'}, | 41 { scriptCode: 'Batk', scriptName: 'Batak'}, |
17 { scriptCode: 'Beng', scriptName: 'Bengali'}, | 42 { scriptCode: 'Beng', scriptName: 'Bengali'}, |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
151 { scriptCode: 'Visp', scriptName: 'Visible Speech'}, | 176 { scriptCode: 'Visp', scriptName: 'Visible Speech'}, |
152 { scriptCode: 'Wara', scriptName: 'Varang Kshiti'}, | 177 { scriptCode: 'Wara', scriptName: 'Varang Kshiti'}, |
153 { scriptCode: 'Wole', scriptName: 'Woleai'}, | 178 { scriptCode: 'Wole', scriptName: 'Woleai'}, |
154 { scriptCode: 'Xpeo', scriptName: 'Old Persian'}, | 179 { scriptCode: 'Xpeo', scriptName: 'Old Persian'}, |
155 { scriptCode: 'Xsux', scriptName: 'Sumero-Akkadian Cuneiform'}, | 180 { scriptCode: 'Xsux', scriptName: 'Sumero-Akkadian Cuneiform'}, |
156 { scriptCode: 'Yiii', scriptName: 'Yi'}, | 181 { scriptCode: 'Yiii', scriptName: 'Yi'}, |
157 { scriptCode: 'Zmth', scriptName: 'Mathematical Notation'}, | 182 { scriptCode: 'Zmth', scriptName: 'Mathematical Notation'}, |
158 { scriptCode: 'Zsym', scriptName: 'Symbols'} | 183 { scriptCode: 'Zsym', scriptName: 'Symbols'} |
159 ]; | 184 ]; |
160 | 185 |
161 // The generic font families supported by the Font Settings Extension API. | 186 /** |
162 var families = | 187 * The generic font families supported by the Font Settings Extension API. |
163 ["standard", "sansserif", "serif", "fixed", "cursive", "fantasy"]; | 188 * @const |
164 | 189 */ |
165 // Mapping between font list ids and the generic family setting they | 190 advancedFonts.FAMILIES = |
166 // represent. | 191 ['standard', 'sansserif', 'serif', 'fixed', 'cursive', 'fantasy']; |
167 var fontPickers = [ | 192 |
168 { fontList: 'standardFontList', name: 'standard' }, | 193 /** |
169 { fontList: 'serifFontList', name: 'serif' }, | 194 * Sample texts. |
170 { fontList: 'sansSerifFontList', name: 'sansserif' }, | 195 * @const |
171 { fontList: 'fixedFontList', name: 'fixed' } | 196 */ |
172 ]; | 197 advancedFonts.SAMPLE_TEXTS = { |
173 | |
174 // Ids of elements to contain the sample text. | |
175 var sampleTextDivIds = [ | |
176 'standardFontSample', | |
177 'serifFontSample', | |
178 'sansSerifFontSample', | |
179 'fixedFontSample', | |
180 'minFontSample' | |
181 ]; | |
182 | |
183 // Sample texts. | |
184 var defaultSampleText = 'The quick brown fox jumps over the lazy dog.'; | |
185 var scriptSpecificSampleText = { | |
186 // "Cyrllic script". | 198 // "Cyrllic script". |
187 'Cyrl': 'Кириллица', | 199 Cyrl: 'Кириллица', |
188 'Hang': '정 참판 양반댁 규수 큰 교자 타고 혼례 치른 날.', | 200 Hang: '정 참판 양반댁 규수 큰 교자 타고 혼례 치른 날.', |
189 'Hans': '床前明月光,疑是地上霜。举头望明月,低头思故乡。', | 201 Hans: '床前明月光,疑是地上霜。举头望明月,低头思故乡。', |
190 'Hant': '床前明月光,疑是地上霜。舉頭望明月,低頭思故鄉。', | 202 Hant: '床前明月光,疑是地上霜。舉頭望明月,低頭思故鄉。', |
191 'Jpan': '吾輩は猫である。名前はまだ無い。', | 203 Jpan: '吾輩は猫である。名前はまだ無い。', |
192 // "Khmer language". | 204 // "Khmer language". |
193 'Khmr': '\u1797\u17B6\u179F\u17B6\u1781\u17D2\u1798\u17C2\u179A', | 205 Khmr: '\u1797\u17B6\u179F\u17B6\u1781\u17D2\u1798\u17C2\u179A', |
194 }; | 206 Zyyy: 'The quick brown fox jumps over the lazy dog.' |
195 | 207 }; |
196 // Definition for ScriptList. | 208 |
197 cr.define('fontSettings.ui', function() { | 209 /** |
198 const List = cr.ui.List; | 210 * Controller of pending changes. |
199 const ListItem = cr.ui.ListItem; | 211 * @const |
200 const ListSingleSelectionModel = cr.ui.ListSingleSelectionModel; | 212 */ |
201 | 213 advancedFonts.pendingChanges = new PendingChanges(); |
202 function ScriptListItem(info) { | 214 |
203 var el = cr.doc.createElement('li'); | 215 /** |
204 el.__proto__ = ScriptListItem.prototype; | 216 * Map from |genericFamily| to UI controls and data for its font setting. |
205 el.info_ = info; | 217 */ |
206 el.decorate(); | 218 advancedFonts.fontSettings = null; |
207 return el; | 219 |
220 /** | |
221 * Map from |fontSizeKey| to UI contols and data for its font size setting. | |
222 */ | |
223 advancedFonts.fontSizeSettings = null; | |
224 | |
225 /** | |
226 * Returns a bound function. | |
227 * @param {function(x, y, z)} callback The function to bind. | |
228 * @param {object} arg2 The argument to pass to the second parameter of | |
229 * |callback|. | |
230 * @param {object} arg3 The argument to pass to the third parameter of | |
231 * |callback|. | |
232 * @return {function(x, y, z)} A function of form function(x, y, z) which calls | |
233 * callback(x, y, z) where |y| and |z| are fixed to |arg2| and |arg3|, | |
234 * respectively. | |
235 */ | |
236 advancedFonts.getBoundCallback = function(callback, arg2, arg3) { | |
237 return function(arg1, ignoredArg2, ignoredArg3) { | |
238 callback(arg1, arg2, arg3) | |
208 }; | 239 }; |
209 | 240 }; |
210 ScriptListItem.prototype = { | 241 |
211 __proto__: ListItem.prototype, | 242 /** |
212 | 243 * Gets the font size used for |fontSizeKey|, including pending changes. Calls |
213 decorate: function() { | 244 * |callback| with the result. |
214 this.textContent = this.info_.scriptName; | 245 * |
215 if (this.info_.scriptCode == 'Zyyy') { | 246 * @param {string} fontSizeKey The font size setting key. See |
216 this.style.marginBottom = '1em'; | 247 * PendingChanges.getFontSize(). |
248 * @param {function(number, boolean)} callback The callback of form | |
249 * function(size, controllable). |size| is the effective setting, | |
250 * |controllable| is whether the setting can be set. | |
251 */ | |
252 advancedFonts.getEffectiveFontSize = function(fontSizeKey, callback) { | |
253 advancedFonts.fontSizeSettings[fontSizeKey].getter({}, function(details) { | |
254 var controllable = advancedFonts.isControllableLevel( | |
255 details.levelOfControl); | |
256 var size = details.pixelSize; | |
257 var pendingFontSize = advancedFonts.pendingChanges.getFontSize(fontSizeKey); | |
258 // If the setting is not controllable, we can have no pending change. | |
259 if (!controllable) { | |
260 if (pendingFontSize != null) { | |
261 advancedFonts.pendingChanges.setFontSize(fontSizeKey, null); | |
262 advancedFonts.refresh(); | |
263 pendingFontSize = null; | |
217 } | 264 } |
218 } | 265 } |
266 | |
267 // If we have a pending change, it overrides the current setting. | |
268 if (pendingFontSize != null) | |
269 size = pendingFontSize; | |
270 callback(size, controllable); | |
271 }); | |
272 }; | |
273 | |
274 /** | |
275 * Gets the font used for |script| and |genericFamily|, including pending | |
276 * changes. Calls |callback| with the result. | |
277 * | |
278 * @param {string} script The script code. | |
279 * @param {string} genericFamily The generic family. | |
280 * @param {function(string, string, boolean)} callback The callback of form | |
281 * function(effectiveFont, font, controllable). |effectiveFont| is the font | |
282 * used taking fallback into consideration, |font| is the actual setting | |
283 * (pending or not), |controllable| is whether the setting can be set. | |
284 */ | |
285 advancedFonts.getEffectiveFont = function(script, genericFamily, callback) { | |
286 var pendingChanges = advancedFonts.pendingChanges; | |
287 var details = { script: script, genericFamily: genericFamily }; | |
288 var pendingFont = | |
289 pendingChanges.getFont(details.script, details.genericFamily); | |
290 chrome.fontSettings.getFont(details, function(result) { | |
291 var setting = {}; | |
292 setting.font = result.fontId; | |
293 setting.controllable = | |
294 advancedFonts.isControllableLevel(result.levelOfControl); | |
295 // If the setting is not controllable, we can have no pending change. | |
296 if (!setting.controllable) { | |
297 pendingFont = null; | |
298 if (pendingChanges.getFont[script]) | |
299 pendingChanges.setFont([script][genericFamily], null); | |
300 refresh(); | |
301 } | |
302 | |
303 // If we have a pending change, it overrides the current setting. | |
304 if (pendingFont != null) | |
305 setting.font = pendingFont; | |
306 | |
307 // If we have a font, we're done. | |
308 if (setting.font) { | |
309 callback(setting.font, setting.font, setting.controllable); | |
310 return; | |
311 } | |
312 | |
313 // If we're still here, we have to fallback to common script, unless this | |
314 // already is common script. | |
315 if (script == advancedFonts.COMMON_SCRIPT) { | |
316 callback('', '', setting.controllable); | |
317 return; | |
318 } | |
319 advancedFonts.getEffectiveFont( | |
320 advancedFonts.COMMON_SCRIPT, | |
321 genericFamily, | |
322 advancedFonts.getBoundCallback( | |
323 callback, setting.font, setting.controllable)); | |
324 }); | |
325 }; | |
326 | |
327 /** | |
328 * Returns a function that refreshes the UI controls related to a font setting. | |
329 * | |
330 * @param {HTMLSelectElement} list The <select> containing the list of fonts. | |
331 * @param {Array.<HTMLElement>} samples Elements with sample text that are | |
332 * rendered using this font setting. | |
333 * @return {function(string, string, boolean)} A function of form | |
334 * function(effectiveFont, font, controllable) that refreshes the UI | |
335 * controls for this font setting. |effectiveFont| is the font used | |
336 * including fallback, |font| is the value of the font setting (including | |
337 * pending changes), |controllable| is whether the setting can be | |
338 * controlled. | |
339 */ | |
340 advancedFonts.getRefreshFontFunction = function(list, samples) { | |
341 return function(effectiveFont, font, controllable) { | |
hirono
2013/08/30 08:57:22
Instead of using closures just for arguments bindi
falken
2013/08/30 10:44:40
That's a good idea. Done.
| |
342 for (var i = 0; i < samples.length; ++i) | |
343 samples[i].style.fontFamily = effectiveFont; | |
344 advancedFonts.setSelectedFont(list, font); | |
345 list.disabled = !controllable; | |
346 } | |
347 } | |
348 | |
349 /** | |
350 * Returns a function that refreshes the UI controls related to a font size | |
351 * setting. | |
352 * | |
353 * @param {string} fontSizeKey The font size setting key. See | |
354 * PendingChanges.getFontSize(). | |
355 * @return {function(number, boolean)} A function of form | |
356 * function(size, controllable) that refreshes the UI controls for this | |
357 * font size setting. |size| is the value of the font size setting | |
358 * (including pending changes), |controllable| is whether the setting can be | |
359 * controlled. | |
360 */ | |
361 advancedFonts.getRefreshFontSizeFunction = function(fontSizeKey) { | |
362 var fontSizeSetting = advancedFonts.fontSizeSettings[fontSizeKey]; | |
363 return function(size, controllable) { | |
364 fontSizeSetting.label.innerText = 'Size: ' + size + 'px'; | |
365 advancedFonts.setFontSizeSlider(fontSizeSetting.slider, size, controllable); | |
366 for (var i = 0; i < fontSizeSetting.samples.length; ++i) | |
367 fontSizeSetting.samples[i].style.fontSize = size + 'px'; | |
219 }; | 368 }; |
220 | 369 }; |
221 var ScriptList = cr.ui.define('list'); | 370 |
222 ScriptList.prototype = { | 371 /** |
223 __proto__: List.prototype, | 372 * Refreshes all UI controls to reflect the current settings, including pending |
224 | 373 * changes. |
225 decorate: function() { | 374 */ |
226 List.prototype.decorate.call(this); | 375 advancedFonts.refresh = function() { |
227 var sm = new ListSingleSelectionModel(); | 376 var script = advancedFonts.getSelectedScript(); |
228 this.selectionModel = sm; | 377 var sample; |
229 this.autoExpands = true; | 378 if (advancedFonts.SAMPLE_TEXTS[script]) |
230 this.dataModel = new cr.ui.ArrayDataModel(scripts); | 379 sample = advancedFonts.SAMPLE_TEXTS[script]; |
231 this.style.height = '75vh'; | 380 else |
232 }, | 381 sample = advancedFonts.SAMPLE_TEXTS[advancedFonts.COMMON_SCRIPT]; |
233 | 382 var sampleTexts = document.querySelectorAll('.sample-text-span'); |
234 createItem: function(info) { | 383 for (var i = 0; i < sampleTexts.length; i++) |
235 return new ScriptListItem(info); | 384 sampleTexts[i].textContent = sample; |
236 } | 385 |
237 }; | 386 var callback; |
238 | 387 for (var genericFamily in advancedFonts.fontSettings) { |
239 return { | 388 var setting = advancedFonts.fontSettings[genericFamily]; |
240 ScriptList: ScriptList, | 389 callback = advancedFonts.getRefreshFontFunction(setting.fontList, |
241 ScriptListItem: ScriptListItem | 390 setting.samples); |
242 }; | 391 advancedFonts.getEffectiveFont(script, genericFamily, callback); |
243 }); | 392 } |
244 | 393 |
245 function getSelectedScript() { | 394 for (var fontSizeKey in advancedFonts.fontSizeSettings) { |
246 var scriptList = document.getElementById('scriptList'); | 395 callback = advancedFonts.getRefreshFontSizeFunction(fontSizeKey); |
247 return scriptList.selectedItem.scriptCode; | 396 advancedFonts.getEffectiveFontSize(fontSizeKey, callback); |
248 } | 397 } |
249 | 398 |
250 function getSelectedFont(fontList) { | 399 $('apply-settings').disabled = advancedFonts.pendingChanges.isEmpty(); |
400 }; | |
401 | |
402 /** | |
403 * @return {string} The currently selected script code. | |
404 */ | |
405 advancedFonts.getSelectedScript = function() { | |
406 var scriptList = $('scriptList'); | |
407 return scriptList.options[scriptList.selectedIndex].value; | |
408 }; | |
409 | |
410 /** | |
411 * @param {HTMLSelectElement} fontList The <select> containing a list of fonts. | |
412 * @return {string} The currently selected value of |fontList|. | |
413 */ | |
414 advancedFonts.getSelectedFont = function(fontList) { | |
251 return fontList.options[fontList.selectedIndex].value; | 415 return fontList.options[fontList.selectedIndex].value; |
252 } | 416 }; |
253 | 417 |
254 // Populates the font lists with the list of system fonts from |fonts|. | 418 /** |
255 function populateLists(fonts) { | 419 * Populates the font lists. |
256 for (var i = 0; i < fontPickers.length; i++) { | 420 * @param {Array.<{fontId: string, displayName: string>} fonts The list of |
257 var list = document.getElementById(fontPickers[i].fontList); | 421 * fonts on the system. |
258 | 422 */ |
259 // Add special item to indicate fallback to the non-per-script | 423 advancedFonts.populateFontLists = function(fonts) { |
424 for (var genericFamily in advancedFonts.fontSettings) { | |
425 var list = advancedFonts.fontSettings[genericFamily].fontList; | |
426 | |
427 // Add a special item to indicate fallback to the non-per-script | |
260 // font setting. The Font Settings API uses the empty string to indicate | 428 // font setting. The Font Settings API uses the empty string to indicate |
261 // fallback. | 429 // fallback. |
262 var defaultItem = document.createElement('option'); | 430 var defaultItem = document.createElement('option'); |
263 defaultItem.value = ''; | 431 defaultItem.value = ''; |
264 defaultItem.text = '(Use default)'; | 432 defaultItem.text = '(Use default)'; |
265 list.add(defaultItem); | 433 list.add(defaultItem); |
266 | 434 |
267 for (var j = 0; j < fonts.length; j++) { | 435 for (var i = 0; i < fonts.length; ++i) { |
268 var item = document.createElement('option'); | 436 var item = document.createElement('option'); |
269 item.value = fonts[j].fontId; | 437 item.value = fonts[i].fontId; |
270 item.text = fonts[j].displayName; | 438 item.text = fonts[i].displayName; |
271 list.add(item); | 439 list.add(item); |
272 } | 440 } |
273 } | 441 } |
442 advancedFonts.refresh(); | |
443 }; | |
274 | 444 |
275 updateFontListsForScript(); | 445 /** |
276 } | 446 * @param {HTMLSelectElement} fontList The <select> containing a list of fonts. |
447 * @param {string} genericFamily The generic family for the font setting. | |
448 * @return {function()} A function to be called when the user changes the | |
449 * selected font in |fontList|. The function updates the pending font | |
450 * change. | |
451 */ | |
452 advancedFonts.getFontChangeHandler = function(fontList, genericFamily) { | |
453 return function() { | |
454 var script = advancedFonts.getSelectedScript(); | |
455 var font = advancedFonts.getSelectedFont(fontList); | |
277 | 456 |
278 // Returns a function that updates the font setting for |genericFamily| | 457 advancedFonts.pendingChanges.setFont(script, genericFamily, font); |
279 // to match the selected value in |fontList|. It can be used as an event | 458 advancedFonts.refresh(); |
280 // handler for selection changes in |fontList|. | 459 }; |
281 function getFontChangeHandler(fontList, genericFamily) { | 460 }; |
282 return function() { | |
283 var script = getSelectedScript(); | |
284 var font = getSelectedFont(fontList); | |
285 | 461 |
286 var details = {}; | 462 /** |
287 details.genericFamily = genericFamily; | 463 * Sets the selected value of |fontList| to |fontId|. |
288 details.fontId = font; | 464 * @param {HTMLSelectElement} fontList The <select> containing a list of fonts. |
289 details.script = script; | 465 * @param {string} fontId The font to set |fontList|'s selection to. |
290 | 466 */ |
291 chrome.fontSettings.setFont(details); | 467 advancedFonts.setSelectedFont = function(fontList, fontId) { |
292 }; | 468 var script = advancedFonts.getSelectedScript(); |
293 } | |
294 | |
295 // Sets the selected value of |fontList| to |fontId|. | |
296 function setSelectedFont(fontList, fontId) { | |
297 var script = getSelectedScript(); | |
298 var i; | 469 var i; |
299 for (i = 0; i < fontList.length; i++) { | 470 for (i = 0; i < fontList.length; i++) { |
300 if (fontId == fontList.options[i].value) { | 471 if (fontId == fontList.options[i].value) { |
301 fontList.selectedIndex = i; | 472 fontList.selectedIndex = i; |
302 break; | 473 break; |
303 } | 474 } |
304 } | 475 } |
305 if (i == fontList.length) { | 476 if (i == fontList.length) { |
306 console.warn("font '" + fontId + "' for " + fontList.id + ' for ' + | 477 console.warn("font '" + fontId + "' for " + fontList.id + ' for ' + |
307 script + ' is not on the system'); | 478 script + ' is not on the system'); |
308 } | 479 } |
309 } | 480 }; |
310 | 481 |
311 // Returns a callback function that sets the selected value of |list| to the | 482 /** |
312 // font returned from |chrome.fontSettings.getFont|. | 483 * Return a function that handles changes to the font size slider. |
313 function getFontHandler(list) { | 484 * @param {string} fontSizeKey The key for font size setting whose slider the |
314 return function(details) { | 485 * function should handle changed for. See PendingChanges.getFont. |
315 setSelectedFont(list, details.fontId); | 486 * @return {function(number)} A function to be called when the user changes the |
316 list.disabled = !isControllableLevel(details.levelOfControl); | 487 * font size slider for |fontSizeKey|. The function sets the pending font |
317 }; | 488 * size change. |
318 } | 489 */ |
319 | 490 advancedFonts.getFontSizeChangedFunc = function(fontSizeKey) { |
320 // Called when the script list selection changes. Sets the selected value of | 491 return function(value) { |
321 // each font list to the current font setting, and updates the samples' lang | 492 var pixelSize = parseInt(value); |
322 // so that they are shown in the current font setting. | |
323 function updateFontListsForScript() { | |
324 var script = getSelectedScript(); | |
325 | |
326 for (var i = 0; i < fontPickers.length; i++) { | |
327 var list = document.getElementById(fontPickers[i].fontList); | |
328 var family = fontPickers[i].name; | |
329 | |
330 var details = {}; | |
331 details.genericFamily = family; | |
332 details.script = script; | |
333 chrome.fontSettings.getFont(details, getFontHandler(list)); | |
334 } | |
335 | |
336 if (typeof(scriptSpecificSampleText[script]) != 'undefined') | |
337 sample = scriptSpecificSampleText[script]; | |
338 else | |
339 sample = defaultSampleText; | |
340 for (var i = 0; i < sampleTextDivIds.length; i++) { | |
341 var sampleTextDiv = document.getElementById(sampleTextDivIds[i]); | |
342 // For font selection it's the script code that matters, not language, so | |
343 // just use en for lang. | |
344 sampleTextDiv.lang = 'en-' + script; | |
345 sampleTextDiv.innerText = sample; | |
346 } | |
347 } | |
348 | |
349 // Returns a function to be called when the user changes the font size | |
350 // input element |elem|. The function calls the Font Settings Extension API | |
351 // function |setter| to commit the change. | |
352 function getFontSizeChangedFunc(elem, setter) { | |
353 return function() { | |
354 var pixelSize = parseInt(elem.value); | |
355 if (!isNaN(pixelSize)) { | 493 if (!isNaN(pixelSize)) { |
356 setter({ pixelSize: pixelSize }); | 494 advancedFonts.pendingChanges.setFontSize(fontSizeKey, pixelSize); |
495 advancedFonts.refresh(); | |
357 } | 496 } |
358 } | 497 } |
359 } | 498 }; |
360 | 499 |
361 function isControllableLevel(levelOfControl) { | 500 /** |
501 * @param {string} levelOfControl The level of control string for a setting, | |
502 * as returned by the Font Settings Extension API. | |
503 * @return {boolean} True if |levelOfControl| signifies that the extension can | |
504 * control the setting; otherwise, returns false. | |
505 */ | |
506 advancedFonts.isControllableLevel = function(levelOfControl) { | |
362 return levelOfControl == 'controllable_by_this_extension' || | 507 return levelOfControl == 'controllable_by_this_extension' || |
363 levelOfControl == 'controlled_by_this_extension'; | 508 levelOfControl == 'controlled_by_this_extension'; |
364 } | 509 }; |
365 | 510 |
366 // Returns a function to be used as a listener for font size setting changed | 511 /** |
367 // events from the Font Settings Extension API. The function updates the input | 512 * Returns a function to be used as a listener for font size setting changed |
368 // element |elem| and the elements in |sampleTexts| to reflect the change. | 513 * events from the Font Settings Extension API. |
369 function getFontSizeChangedOnBrowserFunc(elem, sampleTexts) { | 514 * @param {Slider} slider The slider for the font size setting. |
515 * @param {HTMLElement} label The element that displays the slider's value. | |
516 * @param {Array.<HTMLElement>} sampleTexts Elements containing sample text | |
517 * which are rendered using this font size setting. | |
518 * @return {function(object)} A function that can listen for font size change | |
519 * events from the browser and update |slider|, |label|, and |sampleTexts| | |
520 * to reflect the change. | |
521 */ | |
522 advancedFonts.getFontSizeChangedOnBrowserFunc = | |
523 function(slider, label, sampleTexts) { | |
370 return function(details) { | 524 return function(details) { |
371 var size = details.pixelSize.toString(); | 525 var size = details.pixelSize.toString(); |
372 elem.value = size; | 526 var controllable = |
373 elem.disabled = !isControllableLevel(details.levelOfControl); | 527 advancedFonts.isControllableLevel(details.levelOfControl); |
528 advancedFonts.setFontSizeSlider(slider, size, controllable); | |
529 label.disabled = !controllable; | |
374 for (var i = 0; i < sampleTexts.length; i++) | 530 for (var i = 0; i < sampleTexts.length; i++) |
375 document.getElementById(sampleTexts[i]).style.fontSize = size + 'px'; | 531 sampleTexts[i].style.fontSize = size + 'px'; |
532 label.innerText = 'Size: ' + size + 'px'; | |
376 } | 533 } |
377 } | 534 }; |
378 | 535 |
379 // Maps the HTML <input> element with |id| to the extension API accessor | 536 /* |
380 // functions |getter| and |setter| for a setting and onChange event |apiEvent| | 537 * Updates the specified font size slider's value and enabled property. |
381 // for the setting. Also, maps the element ids in |sampleTexts| to this setting. | 538 * @param {Slider} slider The slider for a font size setting. |
382 function initFontSizePref(id, sampleTexts, getter, setter, apiEvent) { | 539 * @param {number} size The value to set the slider to. |
383 var elem = document.getElementById(id); | 540 * @param {boolean} enabled Whether to enable or disable the slider. |
384 getter({}, function(details) { | 541 */ |
542 advancedFonts.setFontSizeSlider = function(slider, size, enabled) { | |
543 if (slider.getValue() != size) | |
544 slider.setValue(size); | |
545 var inputElement = slider.getInput(); | |
546 if (enabled) { | |
547 inputElement.parentNode.classList.remove('disabled'); | |
548 inputElement.disabled = false; | |
549 } else { | |
550 inputElement.parentNode.classList.add('disabled'); | |
551 inputElement.disabled = true; | |
552 } | |
553 }; | |
554 | |
555 /** | |
556 * Initializes the UI control elements related to the font size setting | |
557 * |fontSizeKey| and registers listeners for the user adjusting its slider and | |
558 * the setting changing on the browser-side. | |
559 * @param {string} fontSizeKey The key for font size setting. See | |
560 * PendingChanges.getFont(). | |
561 */ | |
562 advancedFonts.initFontSizeSetting = function(fontSizeKey) { | |
563 var fontSizeSettings = advancedFonts.fontSizeSettings; | |
564 var setting = fontSizeSettings[fontSizeKey]; | |
565 var label = setting.label; | |
566 var samples = setting.samples; | |
567 | |
568 setting.slider = new Slider( | |
569 setting.sliderContainer, | |
570 0, | |
571 setting.minValue, | |
572 setting.maxValue, | |
573 advancedFonts.getFontSizeChangedFunc(fontSizeKey) | |
574 ); | |
575 | |
576 var slider = setting.slider; | |
577 setting.getter({}, function(details) { | |
385 var size = details.pixelSize.toString(); | 578 var size = details.pixelSize.toString(); |
386 elem.value = size; | 579 var controllable = advancedFonts.isControllableLevel( |
387 elem.disabled = !isControllableLevel(details.levelOfControl); | 580 details.levelOfControl); |
388 for (var i = 0; i < sampleTexts.length; i++) | 581 advancedFonts.setFontSizeSlider(slider, size, controllable); |
389 document.getElementById(sampleTexts[i]).style.fontSize = size + 'px'; | 582 for (var i = 0; i < samples.length; i++) |
583 samples[i].style.fontSize = size + 'px'; | |
390 }); | 584 }); |
391 elem.addEventListener('change', getFontSizeChangedFunc(elem, setter)); | 585 var apiEvent = fontSizeSettings[fontSizeKey].onChanged; |
392 apiEvent.addListener(getFontSizeChangedOnBrowserFunc(elem, sampleTexts)); | 586 apiEvent.addListener( |
393 } | 587 advancedFonts.getFontSizeChangedOnBrowserFunc(slider, label, samples)); |
588 }; | |
394 | 589 |
395 function clearSettingsForScript(script) { | 590 /** |
396 for (var i = 0; i < families.length; i++) { | 591 * Clears the font settings for the specified script. |
592 * @param {string} script The script code. | |
593 */ | |
594 advancedFonts.clearSettingsForScript = function(script) { | |
595 advancedFonts.pendingChanges.clearOneScript(script); | |
596 for (var i = 0; i < advancedFonts.FAMILIES.length; i++) { | |
397 chrome.fontSettings.clearFont({ | 597 chrome.fontSettings.clearFont({ |
398 script: script, | 598 script: script, |
399 genericFamily: families[i] | 599 genericFamily: advancedFonts.FAMILIES[i] |
400 }); | 600 }); |
401 } | 601 } |
402 } | 602 }; |
403 | 603 |
404 function clearAllSettings() { | 604 /** |
405 for (var i = 0; i < scripts.length; i++) | 605 * Clears all font and font size settings. |
406 clearSettingsForScript(scripts[i].scriptCode); | 606 */ |
407 | 607 advancedFonts.clearAllSettings = function() { |
608 advancedFonts.pendingChanges.clear(); | |
609 for (var i = 0; i < advancedFonts.scripts.length; i++) | |
610 advancedFonts.clearSettingsForScript(advancedFonts.scripts[i].scriptCode); | |
408 chrome.fontSettings.clearDefaultFixedFontSize(); | 611 chrome.fontSettings.clearDefaultFixedFontSize(); |
409 chrome.fontSettings.clearDefaultFontSize(); | 612 chrome.fontSettings.clearDefaultFontSize(); |
410 chrome.fontSettings.clearMinimumFontSize(); | 613 chrome.fontSettings.clearMinimumFontSize(); |
411 } | 614 }; |
412 | 615 |
413 function closeOverlay() { | 616 /** |
617 * Closes the overlay. | |
618 */ | |
619 advancedFonts.closeOverlay = function() { | |
414 $('overlay-container').hidden = true; | 620 $('overlay-container').hidden = true; |
415 } | 621 }; |
416 | 622 |
417 function initResetButtons() { | 623 /** |
624 * Initializes apply and reset buttons. | |
625 */ | |
626 advancedFonts.initApplyAndResetButtons = function() { | |
627 var applyButton = $('apply-settings'); | |
628 applyButton.addEventListener('click', function() { | |
629 advancedFonts.pendingChanges.apply(); | |
630 advancedFonts.refresh(); | |
631 }); | |
632 | |
418 var overlay = $('overlay-container'); | 633 var overlay = $('overlay-container'); |
419 cr.ui.overlay.globalInitialization(); | 634 cr.ui.overlay.globalInitialization(); |
420 cr.ui.overlay.setupOverlay(overlay); | 635 cr.ui.overlay.setupOverlay(overlay); |
421 overlay.addEventListener('cancelOverlay', closeOverlay); | 636 overlay.addEventListener('cancelOverlay', advancedFonts.closeOverlay); |
422 | 637 |
423 $('reset-this-script-button').onclick = function(event) { | 638 $('reset-this-script-button').onclick = function(event) { |
424 var scriptName = $('scriptList').selectedItem.scriptName; | 639 var scriptList = $('scriptList'); |
640 var scriptName = scriptList.options[scriptList.selectedIndex].text; | |
425 $('reset-this-script-overlay-dialog-content').innerText = | 641 $('reset-this-script-overlay-dialog-content').innerText = |
426 'Are you sure you want to reset settings for ' + scriptName + | 642 'Are you sure you want to reset settings for ' + scriptName + |
427 ' script?'; | 643 ' script?'; |
428 | 644 |
429 $('overlay-container').hidden = false; | 645 $('overlay-container').hidden = false; |
430 $('reset-this-script-overlay-dialog').hidden = false; | 646 $('reset-this-script-overlay-dialog').hidden = false; |
431 $('reset-all-scripts-overlay-dialog').hidden = true; | 647 $('reset-all-scripts-overlay-dialog').hidden = true; |
432 } | 648 }; |
433 $('reset-this-script-ok').onclick = function(event) { | 649 $('reset-this-script-ok').onclick = function(event) { |
434 clearSettingsForScript(getSelectedScript()); | 650 advancedFonts.clearSettingsForScript(advancedFonts.getSelectedScript()); |
435 closeOverlay(); | 651 advancedFonts.closeOverlay(); |
652 advancedFonts.refresh(); | |
436 }; | 653 }; |
437 $('reset-this-script-cancel').onclick = closeOverlay; | 654 $('reset-this-script-cancel').onclick = advancedFonts.closeOverlay; |
438 | 655 |
439 $('reset-all-button').onclick = function(event) { | 656 $('reset-all-button').onclick = function(event) { |
440 $('overlay-container').hidden = false; | 657 $('overlay-container').hidden = false; |
441 $('reset-all-scripts-overlay-dialog').hidden = false; | 658 $('reset-all-scripts-overlay-dialog').hidden = false; |
442 $('reset-this-script-overlay-dialog').hidden = true; | 659 $('reset-this-script-overlay-dialog').hidden = true; |
660 }; | |
661 $('reset-all-ok').onclick = function(event) { | |
662 advancedFonts.clearAllSettings(); | |
663 advancedFonts.closeOverlay(); | |
664 advancedFonts.refresh(); | |
665 }; | |
666 $('reset-all-cancel').onclick = advancedFonts.closeOverlay; | |
667 }; | |
668 | |
669 /** | |
670 * Best guess for system fonts, taken from the IDS_WEB_FONT_FAMILY strings in | |
671 * Chrome. | |
672 * TODO: The font should be localized like Chrome does. | |
673 * @const | |
674 */ | |
675 advancedFonts.systemFonts = { | |
676 cros: 'Noto Sans UI, sans-serif', | |
677 linux: 'Ubuntu, sans-serif', | |
678 mac: 'Lucida Grande, sans-serif', | |
679 win: 'Segoe UI, Tahoma, sans-serif', | |
680 unknown: 'sans-serif' | |
681 }; | |
682 | |
683 /** | |
684 * @return {string} The platform this extension is running on. | |
685 */ | |
686 advancedFonts.getPlatform = function() { | |
687 var ua = window.navigator.appVersion; | |
688 if (ua.indexOf('Win') != -1) return 'win'; | |
689 if (ua.indexOf('Mac') != -1) return 'mac'; | |
690 if (ua.indexOf('Linux') != -1) return 'linux'; | |
691 if (ua.indexOf('CrOS') != -1) return 'cros'; | |
692 return 'unknown'; | |
693 }; | |
694 | |
695 /** | |
696 * Chrome settings tries to use the system font. So does this extension. | |
697 */ | |
698 advancedFonts.useSystemFont = function() { | |
699 document.body.style.fontFamily = | |
700 advancedFonts.systemFonts[advancedFonts.getPlatform()]; | |
701 }; | |
702 | |
703 /** | |
704 * Sorts the list of script codes by scriptName. Someday this extension will | |
705 * have localized script names, so the order will depend on locale. | |
706 */ | |
707 advancedFonts.sortScripts = function() { | |
708 var i; | |
709 var scripts = advancedFonts.scripts; | |
710 for (i = 0; i < scripts; ++i) { | |
711 if (scripts[i].scriptCode == advancedFonts.COMMON_SCRIPT) | |
712 break; | |
443 } | 713 } |
444 $('reset-all-ok').onclick = function(event) { | 714 var defaultScript = scripts.splice(i, 1)[0]; |
445 clearAllSettings(); | 715 |
446 closeOverlay(); | 716 scripts.sort(function(a, b) { |
717 if (a.scriptName > b.scriptName) | |
718 return 1; | |
719 if (a.scriptName < b.scriptName) | |
720 return -1; | |
721 return 0; | |
722 }); | |
723 | |
724 scripts.unshift(defaultScript); | |
725 }; | |
726 | |
727 /** | |
728 * Initializes UI controls for font settings. | |
729 */ | |
730 advancedFonts.initFontControls = function() { | |
731 advancedFonts.fontSettings = { | |
732 'standard': { | |
hirono
2013/08/30 08:57:22
Remove the quotations.
falken
2013/08/30 10:44:40
Done.
| |
733 fontList: $('standardFontList'), | |
734 samples: [$('standardFontSample'), $('minFontSample')] | |
735 }, | |
736 'serif': { | |
737 fontList: $('serifFontList'), | |
738 samples: [$('serifFontSample')] | |
739 }, | |
740 'sansserif': { | |
741 fontList: $('sansSerifFontList'), | |
742 samples: [$('sansSerifFontSample')] | |
743 }, | |
744 'fixed': { | |
745 fontList: $('fixedFontList'), | |
746 samples: [$('fixedFontSample')] | |
747 } | |
748 }; | |
749 | |
750 for (var genericFamily in advancedFonts.fontSettings) { | |
751 var list = advancedFonts.fontSettings[genericFamily].fontList; | |
752 list.addEventListener('change', advancedFonts.getFontChangeHandler( | |
753 list, genericFamily)); | |
447 } | 754 } |
448 $('reset-all-cancel').onclick = closeOverlay; | 755 chrome.fontSettings.onFontChanged.addListener(advancedFonts.refresh); |
449 } | 756 chrome.fontSettings.getFontList(advancedFonts.populateFontLists); |
757 }; | |
450 | 758 |
451 function init() { | 759 /** |
452 var scriptList = document.getElementById('scriptList'); | 760 * Initializes UI controls for font size settings. |
453 fontSettings.ui.ScriptList.decorate(scriptList); | 761 */ |
454 scriptList.selectionModel.selectedIndex = 0; | 762 advancedFonts.initFontSizeControls = function() { |
455 scriptList.selectionModel.addEventListener('change', | 763 advancedFonts.fontSizeSettings = { |
456 updateFontListsForScript); | 764 'defaultFontSize': { |
hirono
2013/08/30 08:57:22
Remove the quotations.
falken
2013/08/30 10:44:40
Done.
| |
765 sliderContainer: $('defaultFontSizeSliderContainer'), | |
766 minValue: 6, | |
767 maxValue: 50, | |
768 samples: [ | |
769 $('standardFontSample'), $('serifFontSample'), $('sansSerifFontSample') | |
770 ], | |
771 label: $('defaultFontSizeLabel'), | |
772 getter: chrome.fontSettings.getDefaultFontSize, | |
773 onChanged: chrome.fontSettings.onDefaultFontSizeChanged | |
774 }, | |
775 'defaultFixedFontSize': { | |
776 sliderContainer: $('defaultFixedFontSizeSliderContainer'), | |
777 minValue: 6, | |
778 maxValue: 50, | |
779 samples: [$('fixedFontSample')], | |
780 label: $('fixedFontSizeLabel'), | |
781 getter: chrome.fontSettings.getDefaultFixedFontSize, | |
782 onChanged: chrome.fontSettings.onDefaultFixedFontSizeChanged | |
783 }, | |
784 'minFontSize': { | |
785 sliderContainer: $('minFontSizeSliderContainer'), | |
786 minValue: 6, | |
787 maxValue: 24, | |
788 samples: [$('minFontSample')], | |
789 label: $('minFontSizeLabel'), | |
790 getter: chrome.fontSettings.getMinimumFontSize, | |
791 onChanged: chrome.fontSettings.onMinimumFontSizeChanged | |
792 } | |
793 }; | |
457 | 794 |
458 // Populate the font lists. | 795 for (var fontSizeKey in advancedFonts.fontSizeSettings) |
459 chrome.fontSettings.getFontList(populateLists); | 796 advancedFonts.initFontSizeSetting(fontSizeKey); |
797 }; | |
460 | 798 |
461 // Add change handlers to the font lists. | 799 /** |
462 for (var i = 0; i < fontPickers.length; i++) { | 800 * Initializes the list of scripts. |
463 var list = document.getElementById(fontPickers[i].fontList); | 801 */ |
464 var handler = getFontChangeHandler(list, fontPickers[i].name); | 802 advancedFonts.initScriptList = function() { |
465 list.addEventListener('change', handler); | 803 var scriptList = $('scriptList'); |
804 advancedFonts.sortScripts(); | |
805 var scripts = advancedFonts.scripts; | |
806 for (var i = 0; i < scripts.length; i++) { | |
807 var script = document.createElement('option'); | |
808 script.value = scripts[i].scriptCode; | |
809 script.text = scripts[i].scriptName; | |
810 scriptList.add(script); | |
466 } | 811 } |
812 scriptList.selectedIndex = 0; | |
813 scriptList.addEventListener('change', advancedFonts.refresh); | |
814 }; | |
467 | 815 |
468 chrome.fontSettings.onFontChanged.addListener( | 816 /** |
469 updateFontListsForScript); | 817 * Initializes the extension. |
818 */ | |
819 advancedFonts.init = function() { | |
820 advancedFonts.useSystemFont(); | |
470 | 821 |
471 initFontSizePref( | 822 advancedFonts.initFontControls(); |
472 'defaultFontSizeRocker', | 823 advancedFonts.initFontSizeControls(); |
473 ['standardFontSample', 'serifFontSample', 'sansSerifFontSample'], | 824 advancedFonts.initScriptList(); |
474 chrome.fontSettings.getDefaultFontSize, | |
475 chrome.fontSettings.setDefaultFontSize, | |
476 chrome.fontSettings.onDefaultFontSizeChanged); | |
477 initFontSizePref( | |
478 'defaultFontSizeRange', | |
479 ['standardFontSample', 'serifFontSample', 'sansSerifFontSample'], | |
480 chrome.fontSettings.getDefaultFontSize, | |
481 chrome.fontSettings.setDefaultFontSize, | |
482 chrome.fontSettings.onDefaultFontSizeChanged); | |
483 initFontSizePref( | |
484 'defaultFixedFontSizeRocker', | |
485 ['fixedFontSample'], | |
486 chrome.fontSettings.getDefaultFixedFontSize, | |
487 chrome.fontSettings.setDefaultFixedFontSize, | |
488 chrome.fontSettings.onDefaultFixedFontSizeChanged); | |
489 initFontSizePref( | |
490 'defaultFixedFontSizeRange', | |
491 ['fixedFontSample'], | |
492 chrome.fontSettings.getDefaultFixedFontSize, | |
493 chrome.fontSettings.setDefaultFixedFontSize, | |
494 chrome.fontSettings.onDefaultFixedFontSizeChanged); | |
495 initFontSizePref( | |
496 'minFontSizeRocker', | |
497 ['minFontSample'], | |
498 chrome.fontSettings.getMinimumFontSize, | |
499 chrome.fontSettings.setMinimumFontSize, | |
500 chrome.fontSettings.onMinimumFontSizeChanged); | |
501 initFontSizePref( | |
502 'minFontSizeRange', | |
503 ['minFontSample'], | |
504 chrome.fontSettings.getMinimumFontSize, | |
505 chrome.fontSettings.setMinimumFontSize, | |
506 chrome.fontSettings.onMinimumFontSizeChanged); | |
507 | 825 |
508 initResetButtons(); | 826 advancedFonts.initApplyAndResetButtons(); |
509 } | 827 }; |
510 | 828 |
511 document.addEventListener('DOMContentLoaded', init); | 829 document.addEventListener('DOMContentLoaded', advancedFonts.init); |
OLD | NEW |