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 |
208 }; | 220 /** |
209 | 221 * Map from |fontSizeKey| to UI contols and data for its font size setting. |
210 ScriptListItem.prototype = { | 222 */ |
211 __proto__: ListItem.prototype, | 223 advancedFonts.fontSizeSettings = null; |
212 | 224 |
213 decorate: function() { | 225 /** |
214 this.textContent = this.info_.scriptName; | 226 * Gets the font size used for |fontSizeKey|, including pending changes. Calls |
215 if (this.info_.scriptCode == 'Zyyy') { | 227 * |callback| with the result. |
216 this.style.marginBottom = '1em'; | 228 * |
| 229 * @param {string} fontSizeKey The font size setting key. See |
| 230 * PendingChanges.getFontSize(). |
| 231 * @param {function(number, boolean)} callback The callback of form |
| 232 * function(size, controllable). |size| is the effective setting, |
| 233 * |controllable| is whether the setting can be set. |
| 234 */ |
| 235 advancedFonts.getEffectiveFontSize = function(fontSizeKey, callback) { |
| 236 advancedFonts.fontSizeSettings[fontSizeKey].getter({}, function(details) { |
| 237 var controllable = advancedFonts.isControllableLevel( |
| 238 details.levelOfControl); |
| 239 var size = details.pixelSize; |
| 240 var pendingFontSize = advancedFonts.pendingChanges.getFontSize(fontSizeKey); |
| 241 // If the setting is not controllable, we can have no pending change. |
| 242 if (!controllable) { |
| 243 if (pendingFontSize != null) { |
| 244 advancedFonts.pendingChanges.setFontSize(fontSizeKey, null); |
| 245 $('apply-settings').disabled = advancedFonts.pendingChanges.isEmpty(); |
| 246 pendingFontSize = null; |
217 } | 247 } |
218 } | 248 } |
219 }; | 249 |
220 | 250 // If we have a pending change, it overrides the current setting. |
221 var ScriptList = cr.ui.define('list'); | 251 if (pendingFontSize != null) |
222 ScriptList.prototype = { | 252 size = pendingFontSize; |
223 __proto__: List.prototype, | 253 callback(size, controllable); |
224 | 254 }); |
225 decorate: function() { | 255 }; |
226 List.prototype.decorate.call(this); | 256 |
227 var sm = new ListSingleSelectionModel(); | 257 /** |
228 this.selectionModel = sm; | 258 * Gets the font used for |script| and |genericFamily|, including pending |
229 this.autoExpands = true; | 259 * changes. Calls |callback| with the result. |
230 this.dataModel = new cr.ui.ArrayDataModel(scripts); | 260 * |
231 this.style.height = '75vh'; | 261 * @param {string} script The script code. |
232 }, | 262 * @param {string} genericFamily The generic family. |
233 | 263 * @param {function(string, boolean, string)} callback The callback of form |
234 createItem: function(info) { | 264 * function(font, controllable, effectiveFont). |font| is the setting |
235 return new ScriptListItem(info); | 265 * (pending or not), |controllable| is whether the setting can be set, |
236 } | 266 * |effectiveFont| is the font used taking fallback into consideration. |
237 }; | 267 */ |
238 | 268 advancedFonts.getEffectiveFont = function(script, genericFamily, callback) { |
239 return { | 269 var pendingChanges = advancedFonts.pendingChanges; |
240 ScriptList: ScriptList, | 270 var details = { script: script, genericFamily: genericFamily }; |
241 ScriptListItem: ScriptListItem | 271 chrome.fontSettings.getFont(details, function(result) { |
242 }; | 272 var setting = {}; |
243 }); | 273 setting.font = result.fontId; |
244 | 274 setting.controllable = |
245 function getSelectedScript() { | 275 advancedFonts.isControllableLevel(result.levelOfControl); |
246 var scriptList = document.getElementById('scriptList'); | 276 var pendingFont = |
247 return scriptList.selectedItem.scriptCode; | 277 pendingChanges.getFont(details.script, details.genericFamily); |
248 } | 278 // If the setting is not controllable, we can have no pending change. |
249 | 279 if (!setting.controllable) { |
250 function getSelectedFont(fontList) { | 280 if (pendingFont != null) { |
| 281 pendingChanges.setFont(script, genericFamily, null); |
| 282 $('apply-settings').disabled = advancedFonts.pendingChanges.isEmpty(); |
| 283 pendingFont = null; |
| 284 } |
| 285 } |
| 286 |
| 287 // If we have a pending change, it overrides the current setting. |
| 288 if (pendingFont != null) |
| 289 setting.font = pendingFont; |
| 290 |
| 291 // If we have a font, we're done. |
| 292 if (setting.font) { |
| 293 callback(setting.font, setting.controllable, setting.font); |
| 294 return; |
| 295 } |
| 296 |
| 297 // If we're still here, we have to fallback to common script, unless this |
| 298 // already is common script. |
| 299 if (script == advancedFonts.COMMON_SCRIPT) { |
| 300 callback('', setting.controllable, ''); |
| 301 return; |
| 302 } |
| 303 advancedFonts.getEffectiveFont( |
| 304 advancedFonts.COMMON_SCRIPT, |
| 305 genericFamily, |
| 306 callback.bind(null, setting.font, setting.controllable)); |
| 307 }); |
| 308 }; |
| 309 |
| 310 /** |
| 311 * Refreshes the UI controls related to a font setting. |
| 312 * |
| 313 * @param {{fontList: HTMLSelectElement, samples: Array.<HTMLElement>}} |
| 314 * fontSetting The setting object (see advancedFonts.fontSettings). |
| 315 * @param {string} font The value of the font setting. |
| 316 * @param {boolean} controllable Whether the font setting can be controlled |
| 317 * by this extension. |
| 318 * @param {string} effectiveFont The font used, including fallback to Common |
| 319 * script. |
| 320 */ |
| 321 advancedFonts.refreshFont = function( |
| 322 fontSetting, font, controllable, effectiveFont) { |
| 323 for (var i = 0; i < fontSetting.samples.length; ++i) |
| 324 fontSetting.samples[i].style.fontFamily = effectiveFont; |
| 325 advancedFonts.setSelectedFont(fontSetting.fontList, font); |
| 326 fontSetting.fontList.disabled = !controllable; |
| 327 }; |
| 328 |
| 329 /** |
| 330 * Refreshes the UI controls related to a font size setting. |
| 331 * |
| 332 * @param {{label: HTMLElement, slider: Slider, samples: Array.<HTMLElement>}} |
| 333 * fontSizeSetting The setting object (see advancedFonts.fontSizeSettings). |
| 334 * @param size The value of the font size setting. |
| 335 * @param controllable Whether the setting can be controlled by this extension. |
| 336 */ |
| 337 advancedFonts.refreshFontSize = function(fontSizeSetting, size, controllable) { |
| 338 fontSizeSetting.label.textContent = 'Size: ' + size + 'px'; |
| 339 advancedFonts.setFontSizeSlider(fontSizeSetting.slider, size, controllable); |
| 340 for (var i = 0; i < fontSizeSetting.samples.length; ++i) |
| 341 fontSizeSetting.samples[i].style.fontSize = size + 'px'; |
| 342 }; |
| 343 |
| 344 /** |
| 345 * Refreshes all UI controls to reflect the current settings, including pending |
| 346 * changes. |
| 347 */ |
| 348 advancedFonts.refresh = function() { |
| 349 var script = advancedFonts.getSelectedScript(); |
| 350 var sample; |
| 351 if (advancedFonts.SAMPLE_TEXTS[script]) |
| 352 sample = advancedFonts.SAMPLE_TEXTS[script]; |
| 353 else |
| 354 sample = advancedFonts.SAMPLE_TEXTS[advancedFonts.COMMON_SCRIPT]; |
| 355 var sampleTexts = document.querySelectorAll('.sample-text-span'); |
| 356 for (var i = 0; i < sampleTexts.length; i++) |
| 357 sampleTexts[i].textContent = sample; |
| 358 |
| 359 var setting; |
| 360 var callback; |
| 361 for (var genericFamily in advancedFonts.fontSettings) { |
| 362 setting = advancedFonts.fontSettings[genericFamily]; |
| 363 callback = advancedFonts.refreshFont.bind(null, setting); |
| 364 advancedFonts.getEffectiveFont(script, genericFamily, callback); |
| 365 } |
| 366 |
| 367 for (var fontSizeKey in advancedFonts.fontSizeSettings) { |
| 368 setting = advancedFonts.fontSizeSettings[fontSizeKey]; |
| 369 callback = advancedFonts.refreshFontSize.bind(null, setting); |
| 370 advancedFonts.getEffectiveFontSize(fontSizeKey, callback); |
| 371 } |
| 372 |
| 373 $('apply-settings').disabled = advancedFonts.pendingChanges.isEmpty(); |
| 374 }; |
| 375 |
| 376 /** |
| 377 * @return {string} The currently selected script code. |
| 378 */ |
| 379 advancedFonts.getSelectedScript = function() { |
| 380 var scriptList = $('scriptList'); |
| 381 return scriptList.options[scriptList.selectedIndex].value; |
| 382 }; |
| 383 |
| 384 /** |
| 385 * @param {HTMLSelectElement} fontList The <select> containing a list of fonts. |
| 386 * @return {string} The currently selected value of |fontList|. |
| 387 */ |
| 388 advancedFonts.getSelectedFont = function(fontList) { |
251 return fontList.options[fontList.selectedIndex].value; | 389 return fontList.options[fontList.selectedIndex].value; |
252 } | 390 }; |
253 | 391 |
254 // Populates the font lists with the list of system fonts from |fonts|. | 392 /** |
255 function populateLists(fonts) { | 393 * Populates the font lists. |
256 for (var i = 0; i < fontPickers.length; i++) { | 394 * @param {Array.<{fontId: string, displayName: string>} fonts The list of |
257 var list = document.getElementById(fontPickers[i].fontList); | 395 * fonts on the system. |
258 | 396 */ |
259 // Add special item to indicate fallback to the non-per-script | 397 advancedFonts.populateFontLists = function(fonts) { |
| 398 for (var genericFamily in advancedFonts.fontSettings) { |
| 399 var list = advancedFonts.fontSettings[genericFamily].fontList; |
| 400 |
| 401 // 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 | 402 // font setting. The Font Settings API uses the empty string to indicate |
261 // fallback. | 403 // fallback. |
262 var defaultItem = document.createElement('option'); | 404 var defaultItem = document.createElement('option'); |
263 defaultItem.value = ''; | 405 defaultItem.value = ''; |
264 defaultItem.text = '(Use default)'; | 406 defaultItem.text = '(Use default)'; |
265 list.add(defaultItem); | 407 list.add(defaultItem); |
266 | 408 |
267 for (var j = 0; j < fonts.length; j++) { | 409 for (var i = 0; i < fonts.length; ++i) { |
268 var item = document.createElement('option'); | 410 var item = document.createElement('option'); |
269 item.value = fonts[j].fontId; | 411 item.value = fonts[i].fontId; |
270 item.text = fonts[j].displayName; | 412 item.text = fonts[i].displayName; |
271 list.add(item); | 413 list.add(item); |
272 } | 414 } |
273 } | 415 } |
| 416 advancedFonts.refresh(); |
| 417 }; |
274 | 418 |
275 updateFontListsForScript(); | 419 /** |
276 } | 420 * Handles change events on a <select> element for a font setting. |
| 421 * @param {string} genericFamily The generic family for the font setting. |
| 422 * @param {Event} event The change event. |
| 423 */ |
| 424 advancedFonts.handleFontListChange = function(genericFamily, event) { |
| 425 var script = advancedFonts.getSelectedScript(); |
| 426 var font = advancedFonts.getSelectedFont(event.target); |
277 | 427 |
278 // Returns a function that updates the font setting for |genericFamily| | 428 advancedFonts.pendingChanges.setFont(script, genericFamily, font); |
279 // to match the selected value in |fontList|. It can be used as an event | 429 advancedFonts.refresh(); |
280 // handler for selection changes in |fontList|. | 430 }; |
281 function getFontChangeHandler(fontList, genericFamily) { | |
282 return function() { | |
283 var script = getSelectedScript(); | |
284 var font = getSelectedFont(fontList); | |
285 | 431 |
286 var details = {}; | 432 /** |
287 details.genericFamily = genericFamily; | 433 * Sets the selected value of |fontList| to |fontId|. |
288 details.fontId = font; | 434 * @param {HTMLSelectElement} fontList The <select> containing a list of fonts. |
289 details.script = script; | 435 * @param {string} fontId The font to set |fontList|'s selection to. |
290 | 436 */ |
291 chrome.fontSettings.setFont(details); | 437 advancedFonts.setSelectedFont = function(fontList, fontId) { |
292 }; | 438 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; | 439 var i; |
299 for (i = 0; i < fontList.length; i++) { | 440 for (i = 0; i < fontList.length; i++) { |
300 if (fontId == fontList.options[i].value) { | 441 if (fontId == fontList.options[i].value) { |
301 fontList.selectedIndex = i; | 442 fontList.selectedIndex = i; |
302 break; | 443 break; |
303 } | 444 } |
304 } | 445 } |
305 if (i == fontList.length) { | 446 if (i == fontList.length) { |
306 console.warn("font '" + fontId + "' for " + fontList.id + ' for ' + | 447 console.warn("font '" + fontId + "' for " + fontList.id + ' for ' + |
307 script + ' is not on the system'); | 448 script + ' is not on the system'); |
308 } | 449 } |
309 } | 450 }; |
310 | 451 |
311 // Returns a callback function that sets the selected value of |list| to the | 452 /** |
312 // font returned from |chrome.fontSettings.getFont|. | 453 * Handles change events on a font size slider. |
313 function getFontHandler(list) { | 454 * @param {string} fontSizeKey The key for the font size setting whose slider |
314 return function(details) { | 455 * changed. See PendingChanges.getFont. |
315 setSelectedFont(list, details.fontId); | 456 * @param {string} value The new value of the slider. |
316 list.disabled = !isControllableLevel(details.levelOfControl); | 457 */ |
317 }; | 458 advancedFonts.handleFontSizeSliderChange = function(fontSizeKey, value) { |
318 } | 459 var pixelSize = parseInt(value); |
| 460 if (!isNaN(pixelSize)) { |
| 461 advancedFonts.pendingChanges.setFontSize(fontSizeKey, pixelSize); |
| 462 advancedFonts.refresh(); |
| 463 } |
| 464 }; |
319 | 465 |
320 // Called when the script list selection changes. Sets the selected value of | 466 /** |
321 // each font list to the current font setting, and updates the samples' lang | 467 * @param {string} levelOfControl The level of control string for a setting, |
322 // so that they are shown in the current font setting. | 468 * as returned by the Font Settings Extension API. |
323 function updateFontListsForScript() { | 469 * @return {boolean} True if |levelOfControl| signifies that the extension can |
324 var script = getSelectedScript(); | 470 * control the setting; otherwise, returns false. |
325 | 471 */ |
326 for (var i = 0; i < fontPickers.length; i++) { | 472 advancedFonts.isControllableLevel = function(levelOfControl) { |
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)) { | |
356 setter({ pixelSize: pixelSize }); | |
357 } | |
358 } | |
359 } | |
360 | |
361 function isControllableLevel(levelOfControl) { | |
362 return levelOfControl == 'controllable_by_this_extension' || | 473 return levelOfControl == 'controllable_by_this_extension' || |
363 levelOfControl == 'controlled_by_this_extension'; | 474 levelOfControl == 'controlled_by_this_extension'; |
364 } | 475 }; |
365 | 476 |
366 // Returns a function to be used as a listener for font size setting changed | 477 /* |
367 // events from the Font Settings Extension API. The function updates the input | 478 * Updates the specified font size slider's value and enabled property. |
368 // element |elem| and the elements in |sampleTexts| to reflect the change. | 479 * @param {Slider} slider The slider for a font size setting. |
369 function getFontSizeChangedOnBrowserFunc(elem, sampleTexts) { | 480 * @param {number} size The value to set the slider to. |
370 return function(details) { | 481 * @param {boolean} enabled Whether to enable or disable the slider. |
| 482 */ |
| 483 advancedFonts.setFontSizeSlider = function(slider, size, enabled) { |
| 484 if (slider.getValue() != size) |
| 485 slider.setValue(size); |
| 486 var inputElement = slider.getInput(); |
| 487 if (enabled) { |
| 488 inputElement.parentNode.classList.remove('disabled'); |
| 489 inputElement.disabled = false; |
| 490 } else { |
| 491 inputElement.parentNode.classList.add('disabled'); |
| 492 inputElement.disabled = true; |
| 493 } |
| 494 }; |
| 495 |
| 496 /** |
| 497 * Initializes the UI control elements related to the font size setting |
| 498 * |fontSizeKey| and registers listeners for the user adjusting its slider and |
| 499 * the setting changing on the browser-side. |
| 500 * @param {string} fontSizeKey The key for font size setting. See |
| 501 * PendingChanges.getFont(). |
| 502 */ |
| 503 advancedFonts.initFontSizeSetting = function(fontSizeKey) { |
| 504 var fontSizeSettings = advancedFonts.fontSizeSettings; |
| 505 var setting = fontSizeSettings[fontSizeKey]; |
| 506 var label = setting.label; |
| 507 var samples = setting.samples; |
| 508 |
| 509 setting.slider = new Slider( |
| 510 setting.sliderContainer, |
| 511 0, |
| 512 setting.minValue, |
| 513 setting.maxValue, |
| 514 advancedFonts.handleFontSizeSliderChange.bind(null, fontSizeKey) |
| 515 ); |
| 516 |
| 517 var slider = setting.slider; |
| 518 setting.getter({}, function(details) { |
371 var size = details.pixelSize.toString(); | 519 var size = details.pixelSize.toString(); |
372 elem.value = size; | 520 var controllable = advancedFonts.isControllableLevel( |
373 elem.disabled = !isControllableLevel(details.levelOfControl); | 521 details.levelOfControl); |
374 for (var i = 0; i < sampleTexts.length; i++) | 522 advancedFonts.setFontSizeSlider(slider, size, controllable); |
375 document.getElementById(sampleTexts[i]).style.fontSize = size + 'px'; | 523 for (var i = 0; i < samples.length; i++) |
376 } | 524 samples[i].style.fontSize = size + 'px'; |
377 } | 525 }); |
| 526 fontSizeSettings[fontSizeKey].onChanged.addListener(advancedFonts.refresh); |
| 527 }; |
378 | 528 |
379 // Maps the HTML <input> element with |id| to the extension API accessor | 529 /** |
380 // functions |getter| and |setter| for a setting and onChange event |apiEvent| | 530 * Clears the font settings for the specified script. |
381 // for the setting. Also, maps the element ids in |sampleTexts| to this setting. | 531 * @param {string} script The script code. |
382 function initFontSizePref(id, sampleTexts, getter, setter, apiEvent) { | 532 */ |
383 var elem = document.getElementById(id); | 533 advancedFonts.clearSettingsForScript = function(script) { |
384 getter({}, function(details) { | 534 advancedFonts.pendingChanges.clearOneScript(script); |
385 var size = details.pixelSize.toString(); | 535 for (var i = 0; i < advancedFonts.FAMILIES.length; i++) { |
386 elem.value = size; | |
387 elem.disabled = !isControllableLevel(details.levelOfControl); | |
388 for (var i = 0; i < sampleTexts.length; i++) | |
389 document.getElementById(sampleTexts[i]).style.fontSize = size + 'px'; | |
390 }); | |
391 elem.addEventListener('change', getFontSizeChangedFunc(elem, setter)); | |
392 apiEvent.addListener(getFontSizeChangedOnBrowserFunc(elem, sampleTexts)); | |
393 } | |
394 | |
395 function clearSettingsForScript(script) { | |
396 for (var i = 0; i < families.length; i++) { | |
397 chrome.fontSettings.clearFont({ | 536 chrome.fontSettings.clearFont({ |
398 script: script, | 537 script: script, |
399 genericFamily: families[i] | 538 genericFamily: advancedFonts.FAMILIES[i] |
400 }); | 539 }); |
401 } | 540 } |
402 } | 541 }; |
403 | 542 |
404 function clearAllSettings() { | 543 /** |
405 for (var i = 0; i < scripts.length; i++) | 544 * Clears all font and font size settings. |
406 clearSettingsForScript(scripts[i].scriptCode); | 545 */ |
407 | 546 advancedFonts.clearAllSettings = function() { |
| 547 advancedFonts.pendingChanges.clear(); |
| 548 for (var i = 0; i < advancedFonts.scripts.length; i++) |
| 549 advancedFonts.clearSettingsForScript(advancedFonts.scripts[i].scriptCode); |
408 chrome.fontSettings.clearDefaultFixedFontSize(); | 550 chrome.fontSettings.clearDefaultFixedFontSize(); |
409 chrome.fontSettings.clearDefaultFontSize(); | 551 chrome.fontSettings.clearDefaultFontSize(); |
410 chrome.fontSettings.clearMinimumFontSize(); | 552 chrome.fontSettings.clearMinimumFontSize(); |
411 } | 553 }; |
412 | 554 |
413 function closeOverlay() { | 555 /** |
| 556 * Closes the overlay. |
| 557 */ |
| 558 advancedFonts.closeOverlay = function() { |
414 $('overlay-container').hidden = true; | 559 $('overlay-container').hidden = true; |
415 } | 560 }; |
416 | 561 |
417 function initResetButtons() { | 562 /** |
| 563 * Initializes apply and reset buttons. |
| 564 */ |
| 565 advancedFonts.initApplyAndResetButtons = function() { |
| 566 var applyButton = $('apply-settings'); |
| 567 applyButton.addEventListener('click', function() { |
| 568 advancedFonts.pendingChanges.apply(); |
| 569 advancedFonts.refresh(); |
| 570 }); |
| 571 |
418 var overlay = $('overlay-container'); | 572 var overlay = $('overlay-container'); |
419 cr.ui.overlay.globalInitialization(); | 573 cr.ui.overlay.globalInitialization(); |
420 cr.ui.overlay.setupOverlay(overlay); | 574 cr.ui.overlay.setupOverlay(overlay); |
421 overlay.addEventListener('cancelOverlay', closeOverlay); | 575 overlay.addEventListener('cancelOverlay', advancedFonts.closeOverlay); |
422 | 576 |
423 $('reset-this-script-button').onclick = function(event) { | 577 $('reset-this-script-button').onclick = function(event) { |
424 var scriptName = $('scriptList').selectedItem.scriptName; | 578 var scriptList = $('scriptList'); |
| 579 var scriptName = scriptList.options[scriptList.selectedIndex].text; |
425 $('reset-this-script-overlay-dialog-content').innerText = | 580 $('reset-this-script-overlay-dialog-content').innerText = |
426 'Are you sure you want to reset settings for ' + scriptName + | 581 'Are you sure you want to reset settings for ' + scriptName + |
427 ' script?'; | 582 ' script?'; |
428 | 583 |
429 $('overlay-container').hidden = false; | 584 $('overlay-container').hidden = false; |
430 $('reset-this-script-overlay-dialog').hidden = false; | 585 $('reset-this-script-overlay-dialog').hidden = false; |
431 $('reset-all-scripts-overlay-dialog').hidden = true; | 586 $('reset-all-scripts-overlay-dialog').hidden = true; |
432 } | 587 }; |
433 $('reset-this-script-ok').onclick = function(event) { | 588 $('reset-this-script-ok').onclick = function(event) { |
434 clearSettingsForScript(getSelectedScript()); | 589 advancedFonts.clearSettingsForScript(advancedFonts.getSelectedScript()); |
435 closeOverlay(); | 590 advancedFonts.closeOverlay(); |
| 591 advancedFonts.refresh(); |
436 }; | 592 }; |
437 $('reset-this-script-cancel').onclick = closeOverlay; | 593 $('reset-this-script-cancel').onclick = advancedFonts.closeOverlay; |
438 | 594 |
439 $('reset-all-button').onclick = function(event) { | 595 $('reset-all-button').onclick = function(event) { |
440 $('overlay-container').hidden = false; | 596 $('overlay-container').hidden = false; |
441 $('reset-all-scripts-overlay-dialog').hidden = false; | 597 $('reset-all-scripts-overlay-dialog').hidden = false; |
442 $('reset-this-script-overlay-dialog').hidden = true; | 598 $('reset-this-script-overlay-dialog').hidden = true; |
| 599 }; |
| 600 $('reset-all-ok').onclick = function(event) { |
| 601 advancedFonts.clearAllSettings(); |
| 602 advancedFonts.closeOverlay(); |
| 603 advancedFonts.refresh(); |
| 604 }; |
| 605 $('reset-all-cancel').onclick = advancedFonts.closeOverlay; |
| 606 }; |
| 607 |
| 608 /** |
| 609 * Best guess for system fonts, taken from the IDS_WEB_FONT_FAMILY strings in |
| 610 * Chrome. |
| 611 * TODO: The font should be localized like Chrome does. |
| 612 * @const |
| 613 */ |
| 614 advancedFonts.systemFonts = { |
| 615 cros: 'Noto Sans UI, sans-serif', |
| 616 linux: 'Ubuntu, sans-serif', |
| 617 mac: 'Lucida Grande, sans-serif', |
| 618 win: 'Segoe UI, Tahoma, sans-serif', |
| 619 unknown: 'sans-serif' |
| 620 }; |
| 621 |
| 622 /** |
| 623 * @return {string} The platform this extension is running on. |
| 624 */ |
| 625 advancedFonts.getPlatform = function() { |
| 626 var ua = window.navigator.appVersion; |
| 627 if (ua.indexOf('Win') != -1) return 'win'; |
| 628 if (ua.indexOf('Mac') != -1) return 'mac'; |
| 629 if (ua.indexOf('Linux') != -1) return 'linux'; |
| 630 if (ua.indexOf('CrOS') != -1) return 'cros'; |
| 631 return 'unknown'; |
| 632 }; |
| 633 |
| 634 /** |
| 635 * Chrome settings tries to use the system font. So does this extension. |
| 636 */ |
| 637 advancedFonts.useSystemFont = function() { |
| 638 document.body.style.fontFamily = |
| 639 advancedFonts.systemFonts[advancedFonts.getPlatform()]; |
| 640 }; |
| 641 |
| 642 /** |
| 643 * Sorts the list of script codes by scriptName. Someday this extension will |
| 644 * have localized script names, so the order will depend on locale. |
| 645 */ |
| 646 advancedFonts.sortScripts = function() { |
| 647 var i; |
| 648 var scripts = advancedFonts.scripts; |
| 649 for (i = 0; i < scripts; ++i) { |
| 650 if (scripts[i].scriptCode == advancedFonts.COMMON_SCRIPT) |
| 651 break; |
443 } | 652 } |
444 $('reset-all-ok').onclick = function(event) { | 653 var defaultScript = scripts.splice(i, 1)[0]; |
445 clearAllSettings(); | 654 |
446 closeOverlay(); | 655 scripts.sort(function(a, b) { |
| 656 if (a.scriptName > b.scriptName) |
| 657 return 1; |
| 658 if (a.scriptName < b.scriptName) |
| 659 return -1; |
| 660 return 0; |
| 661 }); |
| 662 |
| 663 scripts.unshift(defaultScript); |
| 664 }; |
| 665 |
| 666 /** |
| 667 * Initializes UI controls for font settings. |
| 668 */ |
| 669 advancedFonts.initFontControls = function() { |
| 670 advancedFonts.fontSettings = { |
| 671 standard: { |
| 672 fontList: $('standardFontList'), |
| 673 samples: [$('standardFontSample'), $('minFontSample')] |
| 674 }, |
| 675 serif: { |
| 676 fontList: $('serifFontList'), |
| 677 samples: [$('serifFontSample')] |
| 678 }, |
| 679 sansserif: { |
| 680 fontList: $('sansSerifFontList'), |
| 681 samples: [$('sansSerifFontSample')] |
| 682 }, |
| 683 fixed: { |
| 684 fontList: $('fixedFontList'), |
| 685 samples: [$('fixedFontSample')] |
| 686 } |
| 687 }; |
| 688 |
| 689 for (var genericFamily in advancedFonts.fontSettings) { |
| 690 var list = advancedFonts.fontSettings[genericFamily].fontList; |
| 691 list.addEventListener( |
| 692 'change', advancedFonts.handleFontListChange.bind(list, genericFamily)); |
447 } | 693 } |
448 $('reset-all-cancel').onclick = closeOverlay; | 694 chrome.fontSettings.onFontChanged.addListener(advancedFonts.refresh); |
449 } | 695 chrome.fontSettings.getFontList(advancedFonts.populateFontLists); |
| 696 }; |
450 | 697 |
451 function init() { | 698 /** |
452 var scriptList = document.getElementById('scriptList'); | 699 * Initializes UI controls for font size settings. |
453 fontSettings.ui.ScriptList.decorate(scriptList); | 700 */ |
454 scriptList.selectionModel.selectedIndex = 0; | 701 advancedFonts.initFontSizeControls = function() { |
455 scriptList.selectionModel.addEventListener('change', | 702 advancedFonts.fontSizeSettings = { |
456 updateFontListsForScript); | 703 defaultFontSize: { |
| 704 sliderContainer: $('defaultFontSizeSliderContainer'), |
| 705 minValue: 6, |
| 706 maxValue: 50, |
| 707 samples: [ |
| 708 $('standardFontSample'), $('serifFontSample'), $('sansSerifFontSample') |
| 709 ], |
| 710 label: $('defaultFontSizeLabel'), |
| 711 getter: chrome.fontSettings.getDefaultFontSize, |
| 712 onChanged: chrome.fontSettings.onDefaultFontSizeChanged |
| 713 }, |
| 714 defaultFixedFontSize: { |
| 715 sliderContainer: $('defaultFixedFontSizeSliderContainer'), |
| 716 minValue: 6, |
| 717 maxValue: 50, |
| 718 samples: [$('fixedFontSample')], |
| 719 label: $('fixedFontSizeLabel'), |
| 720 getter: chrome.fontSettings.getDefaultFixedFontSize, |
| 721 onChanged: chrome.fontSettings.onDefaultFixedFontSizeChanged |
| 722 }, |
| 723 minFontSize: { |
| 724 sliderContainer: $('minFontSizeSliderContainer'), |
| 725 minValue: 6, |
| 726 maxValue: 24, |
| 727 samples: [$('minFontSample')], |
| 728 label: $('minFontSizeLabel'), |
| 729 getter: chrome.fontSettings.getMinimumFontSize, |
| 730 onChanged: chrome.fontSettings.onMinimumFontSizeChanged |
| 731 } |
| 732 }; |
457 | 733 |
458 // Populate the font lists. | 734 for (var fontSizeKey in advancedFonts.fontSizeSettings) |
459 chrome.fontSettings.getFontList(populateLists); | 735 advancedFonts.initFontSizeSetting(fontSizeKey); |
| 736 }; |
460 | 737 |
461 // Add change handlers to the font lists. | 738 /** |
462 for (var i = 0; i < fontPickers.length; i++) { | 739 * Initializes the list of scripts. |
463 var list = document.getElementById(fontPickers[i].fontList); | 740 */ |
464 var handler = getFontChangeHandler(list, fontPickers[i].name); | 741 advancedFonts.initScriptList = function() { |
465 list.addEventListener('change', handler); | 742 var scriptList = $('scriptList'); |
| 743 advancedFonts.sortScripts(); |
| 744 var scripts = advancedFonts.scripts; |
| 745 for (var i = 0; i < scripts.length; i++) { |
| 746 var script = document.createElement('option'); |
| 747 script.value = scripts[i].scriptCode; |
| 748 script.text = scripts[i].scriptName; |
| 749 scriptList.add(script); |
466 } | 750 } |
| 751 scriptList.selectedIndex = 0; |
| 752 scriptList.addEventListener('change', advancedFonts.refresh); |
| 753 }; |
467 | 754 |
468 chrome.fontSettings.onFontChanged.addListener( | 755 /** |
469 updateFontListsForScript); | 756 * Initializes the extension. |
| 757 */ |
| 758 advancedFonts.init = function() { |
| 759 advancedFonts.useSystemFont(); |
470 | 760 |
471 initFontSizePref( | 761 advancedFonts.initFontControls(); |
472 'defaultFontSizeRocker', | 762 advancedFonts.initFontSizeControls(); |
473 ['standardFontSample', 'serifFontSample', 'sansSerifFontSample'], | 763 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 | 764 |
508 initResetButtons(); | 765 advancedFonts.initApplyAndResetButtons(); |
509 } | 766 }; |
510 | 767 |
511 document.addEventListener('DOMContentLoaded', init); | 768 document.addEventListener('DOMContentLoaded', advancedFonts.init); |
OLD | NEW |