| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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. | |
| 4 (function(exports) { | |
| 5 /** | |
| 6 * Alignment options for a keyset. | |
| 7 * @param {Object=} opt_keyset The keyset to calculate the dimensions for. | |
| 8 * Defaults to the current active keyset. | |
| 9 */ | |
| 10 var AlignmentOptions = function(opt_keyset) { | |
| 11 var keyboard = document.getElementById('keyboard'); | |
| 12 var keyset = opt_keyset || keyboard.activeKeyset; | |
| 13 this.calculate(keyset); | |
| 14 } | |
| 15 | |
| 16 AlignmentOptions.prototype = { | |
| 17 /** | |
| 18 * The width of a regular key in logical pixels. | |
| 19 * @type {number} | |
| 20 */ | |
| 21 keyWidth: 0, | |
| 22 | |
| 23 /** | |
| 24 * The horizontal space between two keys in logical pixels. | |
| 25 * @type {number} | |
| 26 */ | |
| 27 pitchX: 0, | |
| 28 | |
| 29 /** | |
| 30 * The vertical space between two keys in logical pixels. | |
| 31 * @type {number} | |
| 32 */ | |
| 33 pitchY: 0, | |
| 34 | |
| 35 /** | |
| 36 * The width in logical pixels the row should expand within. | |
| 37 * @type {number} | |
| 38 */ | |
| 39 availableWidth: 0, | |
| 40 | |
| 41 /** | |
| 42 * The x-coordinate in logical pixels of the left most edge of the keyset. | |
| 43 * @type {number} | |
| 44 */ | |
| 45 offsetLeft: 0, | |
| 46 | |
| 47 /** | |
| 48 * The x-coordinate of the right most edge in logical pixels of the keyset. | |
| 49 * @type {number} | |
| 50 */ | |
| 51 offsetRight: 0, | |
| 52 | |
| 53 /** | |
| 54 * The height in logical pixels of all keys. | |
| 55 * @type {number} | |
| 56 */ | |
| 57 keyHeight: 0, | |
| 58 | |
| 59 /** | |
| 60 * The height in logical pixels the keyset should stretch to fit. | |
| 61 * @type {number} | |
| 62 */ | |
| 63 availableHeight: 0, | |
| 64 | |
| 65 /** | |
| 66 * The y-coordinate in logical pixels of the top most edge of the keyset. | |
| 67 * @type {number} | |
| 68 */ | |
| 69 offsetTop: 0, | |
| 70 | |
| 71 /** | |
| 72 * The y-coordinate in logical pixels of the bottom most edge of the keyset. | |
| 73 * @type {number} | |
| 74 */ | |
| 75 offsetBottom: 0, | |
| 76 | |
| 77 /** | |
| 78 * The ideal width of the keyboard container. | |
| 79 * @type {number} | |
| 80 */ | |
| 81 width: 0, | |
| 82 | |
| 83 /** | |
| 84 * The ideal height of the keyboard container. | |
| 85 * @type {number} | |
| 86 */ | |
| 87 height: 0, | |
| 88 | |
| 89 /** | |
| 90 * Recalculates the alignment options for a specific keyset. | |
| 91 * @param {Object} keyset The keyset to align. | |
| 92 */ | |
| 93 calculate: function (keyset) { | |
| 94 var rows = keyset.querySelectorAll('kb-row').array(); | |
| 95 // Pick candidate row. This is the row with the most keys. | |
| 96 var row = rows[0]; | |
| 97 var candidateLength = rows[0].childElementCount; | |
| 98 for (var i = 1; i < rows.length; i++) { | |
| 99 if (rows[i].childElementCount > candidateLength && | |
| 100 rows[i].align == RowAlignment.STRETCH) { | |
| 101 row = rows[i]; | |
| 102 candidateLength = rows[i].childElementCount; | |
| 103 } | |
| 104 } | |
| 105 var allKeys = row.children; | |
| 106 | |
| 107 // Calculates widths first. | |
| 108 // Weight of a single interspace. | |
| 109 var pitches = keyset.pitch.split(); | |
| 110 var pitchWeightX; | |
| 111 var pitchWeightY; | |
| 112 pitchWeightX = parseFloat(pitches[0]); | |
| 113 pitchWeightY = pitches.length < 2 ? pitchWeightX : parseFloat(pitch[1]); | |
| 114 | |
| 115 // Sum of all keys in the current row. | |
| 116 var keyWeightSumX = 0; | |
| 117 for (var i = 0; i < allKeys.length; i++) { | |
| 118 keyWeightSumX += allKeys[i].weight; | |
| 119 } | |
| 120 | |
| 121 var interspaceWeightSumX = (allKeys.length -1) * pitchWeightX; | |
| 122 // Total weight of the row in X. | |
| 123 var totalWeightX = keyWeightSumX + interspaceWeightSumX + | |
| 124 keyset.weightLeft + keyset.weightRight; | |
| 125 var keyAspectRatio = getKeyAspectRatio(); | |
| 126 var totalWeightY = (pitchWeightY * (rows.length - 1)) + | |
| 127 keyset.weightTop + | |
| 128 keyset.weightBottom; | |
| 129 for (var i = 0; i < rows.length; i++) { | |
| 130 totalWeightY += rows[i].weight / keyAspectRatio; | |
| 131 } | |
| 132 // Calculate width and height of the window. | |
| 133 var bounds = exports.getKeyboardBounds(); | |
| 134 | |
| 135 this.width = bounds.width; | |
| 136 this.height = bounds.height; | |
| 137 var pixelPerWeightX = bounds.width/totalWeightX; | |
| 138 var pixelPerWeightY = bounds.height/totalWeightY; | |
| 139 | |
| 140 if (keyset.align == LayoutAlignment.CENTER) { | |
| 141 if (totalWeightX/bounds.width < totalWeightY/bounds.height) { | |
| 142 pixelPerWeightY = bounds.height/totalWeightY; | |
| 143 pixelPerWeightX = pixelPerWeightY; | |
| 144 this.width = Math.floor(pixelPerWeightX * totalWeightX) | |
| 145 } else { | |
| 146 pixelPerWeightX = bounds.width/totalWeightX; | |
| 147 pixelPerWeightY = pixelPerWeightX; | |
| 148 this.height = Math.floor(pixelPerWeightY * totalWeightY); | |
| 149 } | |
| 150 } | |
| 151 // Calculate pitch. | |
| 152 this.pitchX = Math.floor(pitchWeightX * pixelPerWeightX); | |
| 153 this.pitchY = Math.floor(pitchWeightY * pixelPerWeightY); | |
| 154 | |
| 155 // Convert weight to pixels on x axis. | |
| 156 this.keyWidth = Math.floor(DEFAULT_KEY_WEIGHT * pixelPerWeightX); | |
| 157 var offsetLeft = Math.floor(keyset.weightLeft * pixelPerWeightX); | |
| 158 var offsetRight = Math.floor(keyset.weightRight * pixelPerWeightX); | |
| 159 this.availableWidth = this.width - offsetLeft - offsetRight; | |
| 160 | |
| 161 // Calculates weight to pixels on the y axis. | |
| 162 var weightY = Math.floor(DEFAULT_KEY_WEIGHT / keyAspectRatio); | |
| 163 this.keyHeight = Math.floor(weightY * pixelPerWeightY); | |
| 164 var offsetTop = Math.floor(keyset.weightTop * pixelPerWeightY); | |
| 165 var offsetBottom = Math.floor(keyset.weightBottom * pixelPerWeightY); | |
| 166 this.availableHeight = this.height - offsetTop - offsetBottom; | |
| 167 | |
| 168 var dX = bounds.width - this.width; | |
| 169 this.offsetLeft = offsetLeft + Math.floor(dX/2); | |
| 170 this.offsetRight = offsetRight + Math.ceil(dX/2) | |
| 171 | |
| 172 var dY = bounds.height - this.height; | |
| 173 this.offsetBottom = offsetBottom + dY; | |
| 174 this.offsetTop = offsetTop; | |
| 175 }, | |
| 176 }; | |
| 177 | |
| 178 /** | |
| 179 * A simple binary search. | |
| 180 * @param {Array} array The array to search. | |
| 181 * @param {number} start The start index. | |
| 182 * @param {number} end The end index. | |
| 183 * @param {Function<Object>:number} The test function used for searching. | |
| 184 * @private | |
| 185 * @return {number} The index of the search, or -1 if it was not found. | |
| 186 */ | |
| 187 function binarySearch_(array, start, end, testFn) { | |
| 188 if (start > end) { | |
| 189 // No match found. | |
| 190 return -1; | |
| 191 } | |
| 192 var mid = Math.floor((start+end)/2); | |
| 193 var result = testFn(mid); | |
| 194 if (result == 0) | |
| 195 return mid; | |
| 196 if (result < 0) | |
| 197 return binarySearch_(array, start, mid - 1, testFn); | |
| 198 else | |
| 199 return binarySearch_(array, mid + 1, end, testFn); | |
| 200 } | |
| 201 | |
| 202 /** | |
| 203 * Calculate width and height of the window. | |
| 204 * @private | |
| 205 * @return {Array.<String, number>} The bounds of the keyboard container. | |
| 206 */ | |
| 207 function getKeyboardBounds_() { | |
| 208 return { | |
| 209 "width": screen.width, | |
| 210 "height": screen.height * DEFAULT_KEYBOARD_ASPECT_RATIO | |
| 211 }; | |
| 212 } | |
| 213 | |
| 214 /** | |
| 215 * Calculates the desired key aspect ratio based on screen size. | |
| 216 * @return {number} The aspect ratio to use. | |
| 217 */ | |
| 218 function getKeyAspectRatio() { | |
| 219 return (screen.width > screen.height) ? | |
| 220 KEY_ASPECT_RATIO_LANDSCAPE : KEY_ASPECT_RATIO_PORTRAIT; | |
| 221 } | |
| 222 | |
| 223 /** | |
| 224 * Callback function for when the window is resized. | |
| 225 */ | |
| 226 var onResize = function() { | |
| 227 var keyboard = $('keyboard'); | |
| 228 keyboard.stale = true; | |
| 229 var keyset = keyboard.activeKeyset; | |
| 230 if (keyset) | |
| 231 realignAll(); | |
| 232 }; | |
| 233 | |
| 234 /** | |
| 235 * Updates a specific key to the position specified. | |
| 236 * @param {Object} key The key to update. | |
| 237 * @param {number} width The new width of the key. | |
| 238 * @param {number} height The new height of the key. | |
| 239 * @param {number} left The left corner of the key. | |
| 240 * @param {number} top The top corner of the key. | |
| 241 */ | |
| 242 function updateKey(key, width, height, left, top) { | |
| 243 key.style.position = 'absolute'; | |
| 244 key.style.width = width + 'px'; | |
| 245 key.style.height = (height - KEY_PADDING_TOP - KEY_PADDING_BOTTOM) + 'px'; | |
| 246 key.style.left = left + 'px'; | |
| 247 key.style.top = (top + KEY_PADDING_TOP) + 'px'; | |
| 248 } | |
| 249 | |
| 250 /** | |
| 251 * Returns the key closest to given x-coordinate | |
| 252 * @param {Array.<kb-key>} allKeys Sorted array of all possible key | |
| 253 * candidates. | |
| 254 * @param {number} x The x-coordinate. | |
| 255 * @param {number} pitch The pitch of the row. | |
| 256 * @param {boolean} alignLeft whether to search with respect to the left or | |
| 257 * or right edge. | |
| 258 * @return {?kb-key} | |
| 259 */ | |
| 260 function findClosestKey(allKeys, x, pitch, alignLeft) { | |
| 261 // Test function. | |
| 262 var testFn = function(i) { | |
| 263 var ERROR_THRESH = 1; | |
| 264 var key = allKeys[i]; | |
| 265 var left = parseFloat(key.style.left); | |
| 266 if (!alignLeft) | |
| 267 left += parseFloat(key.style.width); | |
| 268 var deltaRight = 0.5*(parseFloat(key.style.width) + pitch) | |
| 269 deltaLeft = 0.5 * pitch; | |
| 270 if (i > 0) | |
| 271 deltaLeft += 0.5*parseFloat(allKeys[i-1].style.width); | |
| 272 var high = Math.ceil(left + deltaRight) + ERROR_THRESH; | |
| 273 var low = Math.floor(left - deltaLeft) - ERROR_THRESH; | |
| 274 if (x <= high && x >= low) | |
| 275 return 0; | |
| 276 return x >= high? 1 : -1; | |
| 277 } | |
| 278 var index = exports.binarySearch(allKeys, 0, allKeys.length -1, testFn); | |
| 279 return index > 0 ? allKeys[index] : null; | |
| 280 } | |
| 281 | |
| 282 /** | |
| 283 * Redistributes the total width amongst the keys in the range provided. | |
| 284 * @param {Array.<kb-key>} allKeys Ordered list of keys to stretch. | |
| 285 * @param {AlignmentOptions} params Options for aligning the keyset. | |
| 286 * @param {number} xOffset The x-coordinate of the key who's index is start. | |
| 287 * @param {number} width The total extraneous width to distribute. | |
| 288 * @param {number} keyHeight The height of each key. | |
| 289 * @param {number} yOffset The y-coordinate of the top edge of the row. | |
| 290 */ | |
| 291 function redistribute(allKeys, params, xOffset, width, keyHeight, yOffset) { | |
| 292 var availableWidth = width - (allKeys.length - 1) * params.pitchX; | |
| 293 var stretchWeight = 0; | |
| 294 var nStretch = 0; | |
| 295 for (var i = 0; i < allKeys.length; i++) { | |
| 296 var key = allKeys[i]; | |
| 297 if (key.stretch) { | |
| 298 stretchWeight += key.weight; | |
| 299 nStretch++; | |
| 300 } else if (key.weight == DEFAULT_KEY_WEIGHT) { | |
| 301 availableWidth -= params.keyWidth; | |
| 302 } else { | |
| 303 availableWidth -= | |
| 304 Math.floor(key.weight/DEFAULT_KEY_WEIGHT * params.keyWidth); | |
| 305 } | |
| 306 } | |
| 307 if (stretchWeight <= 0) | |
| 308 console.error("Cannot stretch row without a stretchable key"); | |
| 309 // Rounding error to distribute. | |
| 310 var pixelsPerWeight = availableWidth / stretchWeight; | |
| 311 for (var i = 0; i < allKeys.length; i++) { | |
| 312 var key = allKeys[i]; | |
| 313 var keyWidth = params.keyWidth; | |
| 314 if (key.weight != DEFAULT_KEY_WEIGHT) { | |
| 315 keyWidth = | |
| 316 Math.floor(key.weight/DEFAULT_KEY_WEIGHT * params.keyWidth); | |
| 317 } | |
| 318 if (key.stretch) { | |
| 319 nStretch--; | |
| 320 if (nStretch > 0) { | |
| 321 keyWidth = Math.floor(key.weight * pixelsPerWeight); | |
| 322 availableWidth -= keyWidth; | |
| 323 } else { | |
| 324 keyWidth = availableWidth; | |
| 325 } | |
| 326 } | |
| 327 updateKey(key, keyWidth, keyHeight, xOffset, yOffset) | |
| 328 xOffset += keyWidth + params.pitchX; | |
| 329 } | |
| 330 } | |
| 331 | |
| 332 /** | |
| 333 * Aligns a row such that the spacebar is perfectly aligned with the row above | |
| 334 * it. A precondition is that all keys in this row can be stretched as needed. | |
| 335 * @param {!kb-row} row The current row to be aligned. | |
| 336 * @param {!kb-row} prevRow The row above the current row. | |
| 337 * @param {!AlignmentOptions} params Options for aligning the keyset. | |
| 338 * @param {number} keyHeight The height of the keys in this row. | |
| 339 * @param {number} heightOffset The height offset caused by the rows above. | |
| 340 */ | |
| 341 function realignSpacebarRow(row, prevRow, params, keyHeight, heightOffset) { | |
| 342 var allKeys = row.children; | |
| 343 var stretchWeightBeforeSpace = 0; | |
| 344 var stretchBefore = 0; | |
| 345 var stretchWeightAfterSpace = 0; | |
| 346 var stretchAfter = 0; | |
| 347 var spaceIndex = -1; | |
| 348 | |
| 349 for (var i=0; i< allKeys.length; i++) { | |
| 350 if (spaceIndex == -1) { | |
| 351 if (allKeys[i].classList.contains('space')) { | |
| 352 spaceIndex = i; | |
| 353 continue; | |
| 354 } else { | |
| 355 stretchWeightBeforeSpace += allKeys[i].weight; | |
| 356 stretchBefore++; | |
| 357 } | |
| 358 } else { | |
| 359 stretchWeightAfterSpace += allKeys[i].weight; | |
| 360 stretchAfter++; | |
| 361 } | |
| 362 } | |
| 363 if (spaceIndex == -1) { | |
| 364 console.error("No spacebar found in this row."); | |
| 365 return; | |
| 366 } | |
| 367 var totalWeight = stretchWeightBeforeSpace + | |
| 368 stretchWeightAfterSpace + | |
| 369 allKeys[spaceIndex].weight; | |
| 370 var widthForKeys = params.availableWidth - | |
| 371 (params.pitchX * (allKeys.length - 1 )) | |
| 372 // Number of pixels to assign per unit weight. | |
| 373 var pixelsPerWeight = widthForKeys/totalWeight; | |
| 374 // Predicted left edge of the space bar. | |
| 375 var spacePredictedLeft = params.offsetLeft + | |
| 376 (spaceIndex * params.pitchX) + | |
| 377 (stretchWeightBeforeSpace * pixelsPerWeight); | |
| 378 var prevRowKeys = prevRow.children; | |
| 379 // Find closest keys to the spacebar in order to align it to them. | |
| 380 var leftKey = | |
| 381 findClosestKey(prevRowKeys, spacePredictedLeft, params.pitchX, true); | |
| 382 | |
| 383 var spacePredictedRight = spacePredictedLeft + | |
| 384 allKeys[spaceIndex].weight * (params.keyWidth/100); | |
| 385 | |
| 386 var rightKey = | |
| 387 findClosestKey(prevRowKeys, spacePredictedRight, params.pitchX, false); | |
| 388 | |
| 389 var yOffset = params.offsetTop + heightOffset; | |
| 390 // Fix left side. | |
| 391 var leftEdge = parseFloat(leftKey.style.left); | |
| 392 var leftWidth = leftEdge - params.offsetLeft - params.pitchX; | |
| 393 var leftKeys = allKeys.array().slice(0, spaceIndex); | |
| 394 redistribute(leftKeys, | |
| 395 params, | |
| 396 params.offsetLeft, | |
| 397 leftWidth, | |
| 398 keyHeight, | |
| 399 yOffset); | |
| 400 // Fix right side. | |
| 401 var rightEdge = parseFloat(rightKey.style.left) + | |
| 402 parseFloat(rightKey.style.width); | |
| 403 var spacebarWidth = rightEdge - leftEdge; | |
| 404 updateKey(allKeys[spaceIndex], | |
| 405 spacebarWidth, | |
| 406 keyHeight, | |
| 407 leftEdge, | |
| 408 yOffset); | |
| 409 var rightWidth = | |
| 410 params.availableWidth - (rightEdge - params.offsetLeft + params.pitchX); | |
| 411 var rightKeys = allKeys.array().slice(spaceIndex + 1); | |
| 412 redistribute(rightKeys, | |
| 413 params, | |
| 414 rightEdge + params.pitchX,//xOffset. | |
| 415 rightWidth, | |
| 416 keyHeight, | |
| 417 yOffset); | |
| 418 } | |
| 419 | |
| 420 /** | |
| 421 * Realigns a given row based on the parameters provided. | |
| 422 * @param {!kb-row} row The row to realign. | |
| 423 * @param {!AlignmentOptions} params The parameters used to align the keyset. | |
| 424 * @param {number} keyHeight The height of the keys. | |
| 425 * @param {number} heightOffset The offset caused by rows above it. | |
| 426 */ | |
| 427 function realignRow(row, params, keyHeight, heightOffset) { | |
| 428 var all = row.children; | |
| 429 var nStretch = 0; | |
| 430 var stretchWeightSum = 0; | |
| 431 var allSum = 0; | |
| 432 // Keeps track of where to distribute pixels caused by round off errors. | |
| 433 var deltaWidth = []; | |
| 434 for (var i = 0; i < all.length; i++) { | |
| 435 deltaWidth.push(0) | |
| 436 var key = all[i]; | |
| 437 if (key.weight == DEFAULT_KEY_WEIGHT){ | |
| 438 allSum += params.keyWidth; | |
| 439 } else { | |
| 440 var width = | |
| 441 Math.floor((params.keyWidth/DEFAULT_KEY_WEIGHT) * key.weight); | |
| 442 allSum += width; | |
| 443 } | |
| 444 if (!key.stretch) | |
| 445 continue; | |
| 446 nStretch++; | |
| 447 stretchWeightSum += key.weight; | |
| 448 } | |
| 449 var nRegular = all.length - nStretch; | |
| 450 // Extra space. | |
| 451 var extra = params.availableWidth - | |
| 452 allSum - | |
| 453 (params.pitchX * (all.length -1)); | |
| 454 var xOffset = params.offsetLeft; | |
| 455 | |
| 456 var alignment = row.align; | |
| 457 switch (alignment) { | |
| 458 case RowAlignment.STRETCH: | |
| 459 var extraPerWeight = extra/stretchWeightSum; | |
| 460 for (var i = 0; i < all.length; i++) { | |
| 461 if (!all[i].stretch) | |
| 462 continue; | |
| 463 var delta = Math.floor(all[i].weight * extraPerWeight); | |
| 464 extra -= delta; | |
| 465 deltaWidth[i] = delta; | |
| 466 // All left-over pixels assigned to right most stretchable key. | |
| 467 nStretch--; | |
| 468 if (nStretch == 0) | |
| 469 deltaWidth[i] += extra; | |
| 470 } | |
| 471 break; | |
| 472 case RowAlignment.CENTER: | |
| 473 xOffset += Math.floor(extra/2) | |
| 474 break; | |
| 475 case RowAlignment.RIGHT: | |
| 476 xOffset += extra; | |
| 477 break; | |
| 478 default: | |
| 479 break; | |
| 480 }; | |
| 481 | |
| 482 var yOffset = params.offsetTop + heightOffset; | |
| 483 var left = xOffset; | |
| 484 for (var i = 0; i < all.length; i++) { | |
| 485 var key = all[i]; | |
| 486 var width = params.keyWidth; | |
| 487 if (key.weight != DEFAULT_KEY_WEIGHT) | |
| 488 width = Math.floor((params.keyWidth/DEFAULT_KEY_WEIGHT) * key.weight) | |
| 489 width += deltaWidth[i]; | |
| 490 updateKey(key, width, keyHeight, left, yOffset) | |
| 491 left += (width + params.pitchX); | |
| 492 } | |
| 493 } | |
| 494 | |
| 495 /** | |
| 496 * Realigns the keysets in all layouts of the keyboard. | |
| 497 */ | |
| 498 function realignAll() { | |
| 499 resizeKeyboardContainer() | |
| 500 var keyboard = $('keyboard'); | |
| 501 var layoutParams = {}; | |
| 502 var idToLayout = function(id) { | |
| 503 var parts = id.split('-'); | |
| 504 parts.pop(); | |
| 505 return parts.join('-'); | |
| 506 } | |
| 507 | |
| 508 var keysets = keyboard.querySelectorAll('kb-keyset').array(); | |
| 509 for (var i=0; i< keysets.length; i++) { | |
| 510 var keyset = keysets[i]; | |
| 511 var layout = idToLayout(keyset.id); | |
| 512 // Caches the layouts size parameters since all keysets in the same layout | |
| 513 // will have the same specs. | |
| 514 if (!(layout in layoutParams)) | |
| 515 layoutParams[layout] = new AlignmentOptions(keyset); | |
| 516 realignKeyset(keyset, layoutParams[layout]); | |
| 517 } | |
| 518 exports.recordKeysets(); | |
| 519 } | |
| 520 | |
| 521 /** | |
| 522 * Realigns the keysets in the current layout of the keyboard. | |
| 523 */ | |
| 524 function realign() { | |
| 525 var keyboard = $('keyboard'); | |
| 526 var params = new AlignmentOptions(); | |
| 527 // Check if current window bounds are accurate. | |
| 528 resizeKeyboardContainer(params) | |
| 529 var layout = keyboard.layout; | |
| 530 var keysets = | |
| 531 keyboard.querySelectorAll('kb-keyset[id^=' + layout + ']').array(); | |
| 532 for (var i = 0; i<keysets.length ; i++) { | |
| 533 realignKeyset(keysets[i], params); | |
| 534 } | |
| 535 keyboard.stale = false; | |
| 536 exports.recordKeysets(); | |
| 537 } | |
| 538 | |
| 539 /** | |
| 540 * Realigns a given keyset. | |
| 541 * @param {Object} keyset The keyset to realign. | |
| 542 * @param {!AlignmentOptions} params The parameters used to align the keyset. | |
| 543 */ | |
| 544 function realignKeyset(keyset, params) { | |
| 545 var rows = keyset.querySelectorAll('kb-row').array(); | |
| 546 keyset.style.fontSize = (params.availableHeight / | |
| 547 FONT_SIZE_RATIO / rows.length) + 'px'; | |
| 548 var heightOffset = 0; | |
| 549 for (var i = 0; i < rows.length; i++) { | |
| 550 var row = rows[i]; | |
| 551 var rowHeight = | |
| 552 Math.floor(params.keyHeight * (row.weight / DEFAULT_KEY_WEIGHT)); | |
| 553 if (row.querySelector('.space') && (i > 1)) { | |
| 554 realignSpacebarRow(row, rows[i-1], params, rowHeight, heightOffset) | |
| 555 } else { | |
| 556 realignRow(row, params, rowHeight, heightOffset); | |
| 557 } | |
| 558 heightOffset += (rowHeight + params.pitchY); | |
| 559 } | |
| 560 } | |
| 561 | |
| 562 /** | |
| 563 * Resizes the keyboard container if needed. | |
| 564 * @params {AlignmentOptions=} opt_params Optional parameters to use. Defaults | |
| 565 * to the parameters of the current active keyset. | |
| 566 */ | |
| 567 function resizeKeyboardContainer(opt_params) { | |
| 568 var params = opt_params ? opt_params : new AlignmentOptions(); | |
| 569 if (Math.abs(window.innerHeight - params.height) > RESIZE_THRESHOLD) { | |
| 570 // Cannot resize more than 50% of screen height due to crbug.com/338829. | |
| 571 window.resizeTo(params.width, params.height); | |
| 572 } | |
| 573 } | |
| 574 | |
| 575 addEventListener('resize', onResize); | |
| 576 addEventListener('load', onResize); | |
| 577 | |
| 578 exports.getKeyboardBounds = getKeyboardBounds_; | |
| 579 exports.binarySearch = binarySearch_; | |
| 580 exports.realignAll = realignAll; | |
| 581 })(this); | |
| 582 | |
| 583 /** | |
| 584 * Recursively replace all kb-key-import elements with imported documents. | |
| 585 * @param {!Document} content Document to process. | |
| 586 */ | |
| 587 function importHTML(content) { | |
| 588 var dom = content.querySelector('template').createInstance(); | |
| 589 var keyImports = dom.querySelectorAll('kb-key-import'); | |
| 590 if (keyImports.length != 0) { | |
| 591 keyImports.array().forEach(function(element) { | |
| 592 if (element.importDoc(content)) { | |
| 593 var generatedDom = importHTML(element.importDoc(content)); | |
| 594 element.parentNode.replaceChild(generatedDom, element); | |
| 595 } | |
| 596 }); | |
| 597 } | |
| 598 return dom; | |
| 599 } | |
| 600 | |
| 601 /** | |
| 602 * Flatten the keysets which represents a keyboard layout. | |
| 603 */ | |
| 604 function flattenKeysets() { | |
| 605 var keysets = $('keyboard').querySelectorAll('kb-keyset'); | |
| 606 if (keysets.length > 0) { | |
| 607 keysets.array().forEach(function(element) { | |
| 608 element.flattenKeyset(); | |
| 609 }); | |
| 610 } | |
| 611 } | |
| 612 | |
| 613 function resolveAudio() { | |
| 614 var keyboard = $('keyboard'); | |
| 615 keyboard.addSound(Sound.DEFAULT); | |
| 616 var nodes = keyboard.querySelectorAll('[sound]').array(); | |
| 617 // Get id's of all unique sounds. | |
| 618 for (var i = 0; i < nodes.length; i++) { | |
| 619 var id = nodes[i].getAttribute('sound'); | |
| 620 keyboard.addSound(id); | |
| 621 } | |
| 622 } | |
| 623 | |
| 624 // Prevents all default actions of touch. Keyboard should use its own gesture | |
| 625 // recognizer. | |
| 626 addEventListener('touchstart', function(e) { e.preventDefault() }); | |
| 627 addEventListener('touchend', function(e) { e.preventDefault() }); | |
| 628 addEventListener('touchmove', function(e) { e.preventDefault() }); | |
| 629 addEventListener('polymer-ready', function(e) { | |
| 630 flattenKeysets(); | |
| 631 resolveAudio(); | |
| 632 }); | |
| 633 addEventListener('stateChange', function(e) { | |
| 634 if (e.detail.value == $('keyboard').activeKeysetId) | |
| 635 realignAll(); | |
| 636 }) | |
| OLD | NEW |