Skip to content

Instantly share code, notes, and snippets.

@OlavHN
Created January 9, 2013 15:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OlavHN/4493809 to your computer and use it in GitHub Desktop.
Save OlavHN/4493809 to your computer and use it in GitHub Desktop.
Files: apps/keyboard/style/keyboard.css apps/keyboard/js/render.js 1. Open Contacts 2. Click Mobile -> Phone 3. Hold down button with alt key I expected it to be a highlighted alternative, but it turns out to render the key above the highlighting or something similar.
/* Media definitions */
@media screen and (max--moz-device-pixel-ratio: 1.5) {
html {
font-size: 15px;
}
}
@font-face {
font-family: 'Keyboard Symbols';
font-weight: 600;
src: url('fonts/Keyboard-Symbols.woff');
}
/* Reset */
* {
margin: 0;
padding: 0;
}
html {
pointer-events: none;
}
body {
overflow: hidden;
}
button::-moz-focus-inner {
padding: 0;
border: 0
}
.cache {
position: absolute;
left: 0;
bottom: 0;
z-index: -1;
opacity: 0;
overflow: hidden;
width: 0;
height: 0;
display: none;
}
/* Keyboard */
#keyboard {
position: absolute;
bottom: 0;
z-index: 15;
width: 100%;
background: #6a6f73;
border-top: solid 1px #000;
pointer-events: auto;
}
/* Rows */
.keyboard-row {
width: 100%;
margin-bottom: 0.5rem;
white-space: nowrap;
}
.keyboard-row.first-row {
padding-top: 0.5rem;
border-top: solid 1px #a6a9ab;
}
/* Buttons: logic keys */
.keyboard-key {
-moz-box-sizing: border-box;
padding: 0 0.1rem;
border: none;
background: url(images/key-shadow.png) no-repeat center -1px;
background-size: 100% 100%;
min-width: 2.6rem;
display: inline-block;
}
/* Visible keys */
.keyboard-key > .visual-wrapper {
display: inline-block;
height: 4rem;
width: 100%;
-moz-box-sizing: border-box;
position: relative;
border: solid 1px #000;
background: #252220 url(images/key-bg.png) no-repeat center bottom;
background-size: 100% 100%;
}
/* Standard key styles. */
.keyboard-key > .visual-wrapper > span {
/*
top - begin | top - end
bottom - begin | bottom - end
*/
background:
url(images/key-radius-tb.png) no-repeat left top,
url(images/key-radius-te.png) no-repeat right top,
url(images/key-radius-bb.png) no-repeat left bottom,
url(images/key-radius-be.png) no-repeat right bottom,
url(images/key-light.png) repeat-x left 1px;
position: absolute;
top: -1px;
bottom: -1px;
left: -1px;
right: -1px;
font: 2.4rem/3.5rem MozTT, Sans-serif;
font-weight: 500;
text-align: center;
color: #fff;
}
/* Highlights */
.keyboard-key:not(.special-key).highlighted {
position: relative;
z-index: 100;
}
.keyboard-key:not(.special-key).highlighted > .visual-wrapper {
background: #6ec5d5;
border-radius: 0 0 0.3rem 0.3rem;
border: solid 1px #8BD1DD;
border-top: none;
margin: -0.5rem 0 0;
height: 4.3rem;
}
.keyboard-key:not(.special-key).highlighted > .visual-wrapper:after {
content: "";
position: absolute;
left: -0.5rem;
top: 0.5rem;
bottom: -0.5rem;
right: -0.5rem;
z-index: -1;
background: url(images/dark-alpha.png) repeat left top;
border-radius: 0.6rem;
}
.keyboard-key:not(.special-key).highlighted:last-child > .visual-wrapper:after {
right: -0.2rem;
border-radius: 0.6rem 0 0 0.6rem;
}
.keyboard-key:not(.special-key).highlighted > .visual-wrapper:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 0.5rem;
background: #6ec5d5;
z-index: 1;
}
.keyboard-key:not(.special-key).highlighted > .visual-wrapper > span {
font: 3.8rem/4.5rem MozTT, Sans-serif;
font-weight: 500;
background: #6ec5d5;
color: #1a3f46;
border: solid 1px #8BD1DD;
border-radius: 0.3rem;
height: 5.2rem;
top: -5.3rem;
left: -0.8rem;
right: -0.8rem;
}
.keyboard-key:not(.special-key).highlighted > .visual-wrapper > span:after {
content: "";
position: absolute;
left: -0.5rem;
top: -0.5rem;
bottom: -0.5rem;
right: -0.5rem;
z-index: -1;
background: url(images/dark-alpha.png) repeat left top;
border-radius: 0.6rem;
}
.keyboard-key:not(.special-key).highlighted:last-child > .visual-wrapper > span:after {
right: -0.2rem;
border-radius: 0.6rem 0 0 0.6rem;
}
.keyboard-key:not(.special-key).highlighted:last-child > .visual-wrapper > span {
right: -1px;
border-bottom-right-radius: 0;
}
.keyboard-key:not(.special-key).highlighted:last-child #keyboard-accent-char-menu {
right: -1px;
}
.keyboard-key:not(.special-key).highlighted:first-child > .visual-wrapper > span {
left: -1px;
border-bottom-left-radius: 0;
}
.keyboard-key:not(.special-key).highlighted:first-child #keyboard-accent-char-menu {
left: -1px;
}
/* Special keys */
.keyboard-key.special-key > .visual-wrapper {
border-color: #2a2c2e;
background: #43474a;
}
.keyboard-key.special-key > .visual-wrapper > span {
/*
top - begin | top - end
bottom - begin | bottom - end
*/
background:
url(images/key-radius-special-tb.png) no-repeat left top,
url(images/key-radius-special-te.png) no-repeat right top,
url(images/key-radius-special-bb.png) no-repeat left bottom,
url(images/key-radius-special-be.png) no-repeat right bottom,
url(images/key-light-special.png) repeat-x left 1px;
font-size: 1.5rem;
line-height: 4rem;
font-family: 'Keyboard Symbols', sans-serif;
color: #ccc;
}
/* Highlight for special keys */
.keyboard-key.special-key.highlighted > .visual-wrapper {
background: #4AB6CB;
border-radius: 0.3rem;
border: solid 1px #3f5459;
}
.keyboard-key.special-key.highlighted > .visual-wrapper > span {
background: none;
color: #1e4a52;
}
.keyboard-key.special-key.highlighted > .visual-wrapper:before {
content: "";
position: absolute;
left: -0.2rem;
right: -0.2rem;
top: -0.2rem;
bottom: -0.25rem;
z-index: -1;
background: #4495A8;
border-radius: 0.3rem;
}
/*Olav*/
.keyboard-key.highlighted-big-key > .visual-wrapper {
background: #4AB6CB;
border-radius: 0.3rem;
border: solid 1px #3f5459;
}
.keyboard-key.highlighted-big-key > .visual-wrapper > span {
background: none;
color: #1e4a52;
}
.keyboard-key.highlighted-big-key > .visual-wrapper:before {
content: "";
position: absolute;
left: -0.2rem;
right: -0.2rem;
top: -0.2rem;
bottom: -0.25rem;
z-index: -1;
background: #4495A8;
border-radius: 0.3rem;
}
/*Olav end*/
/* Spacebar exceptions */
.keyboard-key[data-keycode="32"] > .visual-wrapper {
background-position: center 2.2rem;
}
.keyboard-key.highlighted[data-keycode="32"] > .visual-wrapper {
border: solid 1px #000;
border-radius: 0.3rem;
background: #252220 url(images/key-bg.png) no-repeat center 2.2rem;
background-size: 100% 100%;
opacity: 0.5;
margin: 0;
height: 4rem;
}
.keyboard-key.highlighted[data-keycode="32"] > .visual-wrapper > span {
border: none;
border-top: solid 1px #514e4d;
background: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
height: 100%;
}
.keyboard-key.highlighted[data-keycode="32"] > .visual-wrapper:after,
.keyboard-key.highlighted[data-keycode="32"] > .visual-wrapper:before,
.keyboard-key.highlighted[data-keycode="32"] > .visual-wrapper > span:after {
display: none;
}
/* Key states */
/* Active */
.keyboard-key.kbr-key-active > .visual-wrapper > span {
color: #4495A8;
}
/* Hold */
.keyboard-key.kbr-key-hold> .visual-wrapper {
background: #4AB6CB;
border-radius: 0.3rem;
border: solid 1px #3f5459;
}
.keyboard-key.kbr-key-hold> .visual-wrapper > span {
background: none;
color: #1e4a52;
}
/* Alt menu enabled */
.keyboard-key.highlighted.kbr-menu-on > .visual-wrapper {
background: #6EC5D5;
border: 1px solid #92D3E0;
border-top: none;
height: 4.5rem;
}
.keyboard-key.highlighted.kbr-menu-on > .visual-wrapper > span:after {
display: none;
}
.keyboard-key.highlighted.kbr-menu-on > .visual-wrapper:before {
background: #6EC5D5;
}
.keyboard-key.highlighted.kbr-menu-on > .visual-wrapper > span {
background: transparent;
border-color: transparent;
}
/* Alternatives menu -- this menu appears when you tap and hold a key that has
alternative special (accented) characters. The menu "grows" out of the key
and displays the list of alternatives. */
#keyboard-accent-char-menu {
position: absolute;
bottom: 0;
left: 0.6rem;
margin-bottom: -1px;
height: 5.8rem;
border-radius: 0.3rem;
background: #333;
border: 1px solid #000;
white-space: nowrap;
overflow: visible;
display: none;
}
#keyboard-accent-char-menu:after {
content: "";
position: absolute;
left: -0.5rem;
top: -0.5rem;
bottom: -0.6rem;
right: -0.5rem;
z-index: -1;
background: url(images/dark-alpha.png) repeat left top;
border-radius: 0.6rem 0.6rem 0.6rem 0;
}
.keyboard-key:first-child #keyboard-accent-char-menu {
border-radius: 0.3rem 0.3rem 0.3rem 0;
}
.keyboard-key:last-child #keyboard-accent-char-menu {
border-radius: 0.3rem 0.3rem 0 0.3rem;
}
#keyboard-accent-char-menu.show {
display: block;
}
/* Alternatives from right */
#keyboard-accent-char-menu.kbr-menu-right {
left: auto;
right: 0.6rem;
}
/* Non keyboard key styles in menu */
#keyboard-accent-char-menu .keyboard-key {
background: none;
height: 100%;
vertical-align: top;
top: -1px;
position: relative;
}
#keyboard-accent-char-menu .keyboard-key:first-child {
padding-left: 0;
}
#keyboard-accent-char-menu .keyboard-key.highlighted:first-child > .visual-wrapper {
left: -1px;
}
#keyboard-accent-char-menu .keyboard-key:last-child {
padding-right: 0;
}
#keyboard-accent-char-menu .keyboard-key.highlighted:last-child > .visual-wrapper {
border-right: none;
right: 1px;
}
#keyboard-accent-char-menu .keyboard-key > .visual-wrapper {
background: none;
border: none;
border-radius: 0;
margin: 0;
height: 5.8rem;
}
#keyboard-accent-char-menu .keyboard-key > .visual-wrapper span {
background: none;
}
#keyboard-accent-char-menu .keyboard-key.highlighted > .visual-wrapper:after,
#keyboard-accent-char-menu .keyboard-key.highlighted > .visual-wrapper:before,
#keyboard-accent-char-menu .keyboard-key.highlighted > .visual-wrapper > span:after {
display: none;
}
/* Styles for keys in accent menu (not highlighted). */
#keyboard-accent-char-menu .keyboard-key > .visual-wrapper > span {
border: none;
font: 3rem/5rem MozTT, Sans-serif;
font-weight: 500;
color: #fff;
}
/* Highlighted non keboard key style */
#keyboard-accent-char-menu .keyboard-key.highlighted > .visual-wrapper {
background: #6ec5d5;
border: solid 0.2rem #6ec5d5;
-moz-box-sizing: content-box;
border-top: solid 1px #8BD1DD;
border-bottom: solid 1px #6ec5d5;
}
/* Highlighted special accent characters. These keys appear in the popover
bubble above the key when you tap and hold. */
#keyboard-accent-char-menu .keyboard-key.highlighted > .visual-wrapper > span {
top: 0;
left: 0;
right: 0;
z-index: 1;
height: 100%;
font-weight: normal;
color: #1a3f46;
background: none;
}
/* Language alternatives */
#keyboard-accent-char-menu.kbr-menu-lang {
position: absolute;
bottom: 100%;
left: 0;
right: auto;
top: auto;
margin-bottom: -2px;
height: auto;
max-height: 34rem;
white-space: normal;
}
/* Special key menu enabled */
.keyboard-key.special-key.highlighted.kbr-menu-on {
position: relative;
z-index: 100;
}
.keyboard-key.special-key.highlighted.kbr-menu-on > .visual-wrapper {
border-radius: 0 0 0.3rem 0.3rem;
margin-top: -0.5rem;
}
.keyboard-key.special-key.highlighted.kbr-menu-on > .visual-wrapper > span {
color: #fff;
line-height: 5.2rem;
border: none;
}
.keyboard-key.special-key.highlighted.kbr-menu-on > .visual-wrapper:after {
content: "";
position: absolute;
left: -0.5rem;
top: 0.5rem;
bottom: -0.5rem;
right: -0.5rem;
z-index: -1;
background: url(images/dark-alpha.png) repeat left top;
border-radius: 0.6rem;
}
.keyboard-key.special-key.highlighted.kbr-menu-on > .visual-wrapper:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 0.5rem;
z-index: 1;
}
#keyboard-accent-char-menu.kbr-menu-lang > .keyboard-key {
padding: 0;
display: block;
height: 4rem;
top: 0;
}
#keyboard-accent-char-menu.kbr-menu-lang > .keyboard-key > .visual-wrapper {
-moz-box-sizing: border-box;
border: none;
border-bottom: solid 1px #92D3E0;
width: 10rem;
height: 4rem;
}
#keyboard-accent-char-menu.kbr-menu-lang > .keyboard-key:first-child > .visual-wrapper {
border-radius: 0.3rem 0.3rem 0 0;
}
#keyboard-accent-char-menu.kbr-menu-lang > .keyboard-key.highlighted > .visual-wrapper {
left: 0;
right: 0;
}
#keyboard-accent-char-menu.kbr-menu-lang > .keyboard-key > .visual-wrapper > span {
font-family: 'MozTT', Sans-serif;
font-weight: 500;
font-size: 1.8rem;
line-height: 4rem;
}
#keyboard-accent-char-menu.kbr-menu-lang > .keyboard-key:last-child {
margin-bottom: 0.8rem;
}
#keyboard-accent-char-menu.kbr-menu-lang > .keyboard-key.kbr-key-hold > .visual-wrapper {
background: #333;
}
#keyboard-accent-char-menu.kbr-menu-lang > .keyboard-key.kbr-key-hold > .visual-wrapper > span {
color: #fff;
}
/* IMEs */
#keyboard-pending-symbol-panel {
position: absolute;
top: -35px;
left: 0;
height: 32px;
line-height: 32px;
font-size: 24px;
width: auto;
padding: 0 8px;
background: rgba(245, 245, 245, 0.7);
color: rgb(36, 36, 36);
border-top-right-radius: 8px;
border-top: 1px solid #d5d5d5;
border-right: 1px solid #d5d5d5;
white-space: nowrap;
}
#keyboard-pending-symbol-panel:empty {
display: none;
}
#keyboard-candidate-panel {
height: 64px;
overflow: auto;
white-space: nowrap;
color: black;
background: rgb(176, 174, 168);
border-top: 1px solid #e8e8ff;
border-bottom: 1px solid #808098;
display: none;
margin: 0 -1rem 0 -1rem;
}
#keyboard.candidate-panel #keyboard-candidate-panel {
display: block;
width: -moz-calc(100% - 62px + 1rem);
overflow-y: hidden;
}
/* for latin suggestions we don't need such a tall box */
/* and in latin we hide the toggle button, so we can be full-width */
#keyboard.candidate-panel #keyboard-candidate-panel.latin {
height: 30px;
width: 100%;
background: none;
margin: 0;
border: none;
}
#keyboard.full-candidate-panel {
padding-top: 66px;
}
#keyboard.full-candidate-panel #keyboard-candidate-panel {
display: block;
position: absolute;
white-space: normal;
top: 0;
height: 100%;
width: 100%;
border: none;
border-top: 2px solid #a3a3a3;
z-index: 1;
margin:0; padding:0;
overflow-x: hidden;
overflow-y: auto;
}
#keyboard.full-candidate-panel #keyboard-candidate-panel span {
border-top: 1px solid #e8e8ff;
border-bottom: 1px solid #808098;
}
#keyboard-candidate-panel[data-truncated]::after {
content: '…';
background: none ! important;
border-color: transparent ! important;
color: #666;
}
#keyboard-candidate-panel span,
#keyboard-candidate-panel[data-truncated]::after {
border-left: 1px solid #e8e8ff;
border-right: 1px solid #808098;
font-size: 32px;
line-height: 60px;
min-width: 60px;
display: inline-block;
height: 64px;
padding: 0 10px;
text-align: center;
background: -moz-linear-gradient(top, rgb(191,191,183) 10%, rgb(161,158,153) 90%);
}
#keyboard-candidate-panel.latin span,
#keyboard-candidate-panel[data-truncated].latin::after {
font-family: 'MozTT', sans-serif;
font-size: 10pt;
line-height: 24px;
height: 24px;
border: none;
border-radius: 4px;
margin: 3px;
}
#keyboard-candidate-panel-toggle-button {
border-left: 1px solid #e8e8ff;
border-right: 1px solid #808098;
border-bottom: 1px solid #808098;
position: absolute;
font-size: 32px;
line-height: 60px;
right: 0;
top: 1px;
text-align: center;
box-shadow: -4px 0 5px -5px black;
width: 60px;
height: 64px;
color: black;
background: -moz-linear-gradient(top, rgb(191,191,183) 10%, rgb(161,158,153) 90%);
display: none;
}
#keyboard.full-candidate-panel #keyboard-candidate-panel-toggle-button {
display: block;
border-top: 1px solid #e8e8ff;
top: 0;
z-index: 1;
}
#keyboard.candidate-panel #keyboard-candidate-panel-toggle-button {
display: block;
}
/*
* Don't display the toggle button for latin suggestions.
* For now, at least, we only ever get 3 at a time
*/
#keyboard.candidate-panel #keyboard-candidate-panel-toggle-button.latin {
display: none;
}
#keyboard-candidate-panel span[data-active],
#keyboard-candidate-panel-toggle-button[data-active] {
background: -moz-linear-gradient(bottom, rgb(191,191,183) 10%, rgb(161,158,153) 90%);
}
/* Pending panel highlight */
.keyboard-pending-symbols-highlight-green {
background: #33aa33;
}
.keyboard-pending-symbols-highlight-red {
background: #aa3333;
}
.keyboard-pending-symbols-highlight-blue {
background: #3333aa;
}
/* A note to show on the key to indicate the alternative char */
.alt-note {
position: absolute;
top: 0.5rem;
right: 0.5rem;
color: #999;
font: 1.6rem/1.6rem "Keyboard Symbols", Sans-serif;
}
.keyboard-key.highlighted .alt-note {
visibility: hidden;
}
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
'use strict';
// Render is in charge of draw and composite HTML elements under requestion
// of the IMEController. IMERender is able to read from the layout to improve
// its performance but is not allowed to communicate with the controller nor
// manager.
//
// XXX: The only thing worth to be remebered is the KEY element must be the
// deepest interactive HTML element on the hierarchy or, if none, simply the
// deepest element. This element must contain dataset-keycode and related
// attributes.
const IMERender = (function() {
var ime, menu, pendingSymbolPanel, candidatePanel, candidatePanelToggleButton;
var getUpperCaseValue, isSpecialKey;
var _menuKey, _altContainer;
var layoutWidth = 10;
var inputType;
var inputMethodName; // used as a CSS class on the candidatePanel
// Initiaze the render. It needs some business logic to determine:
// 1- The uppercase for a key object
// 2- When a key is a special key
var init = function kr_init(uppercaseFunction, keyTest) {
getUpperCaseValue = uppercaseFunction;
isSpecialKey = keyTest;
this.ime = document.getElementById('keyboard');
}
var setInputMethodName = function(name) {
var candidatePanel = document.getElementById('keyboard-candidate-panel');
if (candidatePanel) {
if (inputMethodName)
candidatePanel.classList.remove(inputMethodName);
candidatePanel.classList.add(name);
}
var togglebutton =
document.getElementById('keyboard-candidate-panel-toggle-button');
if (togglebutton) {
if (inputMethodName)
togglebutton.classList.remove(inputMethodName);
togglebutton.classList.add(name);
}
inputMethodName = name;
}
// Accepts three values: true / 'locked' / false
// Use 'locked' when caps are locked
// Use true when uppercase is enabled
// Use false when uppercase if disabled
var setUpperCaseLock = function kr_setUpperCaseLock(state) {
var capsLockKey = document.querySelector(
'button[data-keycode="' + KeyboardEvent.DOM_VK_CAPS_LOCK + '"]'
);
if (!capsLockKey)
return;
if (state === 'locked') {
capsLockKey.classList.remove('kbr-key-active');
capsLockKey.classList.add('kbr-key-hold');
} else if (state) {
capsLockKey.classList.add('kbr-key-active');
capsLockKey.classList.remove('kbr-key-hold');
} else {
capsLockKey.classList.remove('kbr-key-active');
capsLockKey.classList.remove('kbr-key-hold');
}
}
// Draw the keyboard and its components. Meat is here.
var draw = function kr_draw(layout, flags) {
flags = flags || {};
// change scale (Our target screen width is 320px)
// TODO get document.documentElement.style.fontSize
// and use it for multipling changeScale deppending on the value of pixel
// density used in media queries
var content = '';
layoutWidth = layout.width || 10;
var totalWidth = document.getElementById('keyboard').clientWidth;
var placeHolderWidth = totalWidth / layoutWidth;
inputType = flags.inputType || 'text';
layout.upperCase = layout.upperCase || {};
var first = true;
layout.keys.forEach((function buildKeyboardRow(row, nrow) {
var firstRow = '';
if (first) {
firstRow = ' first-row';
first = false;
}
content += '<div class="keyboard-row' + firstRow + '">';
row.forEach((function buildKeyboardColumns(key, ncolumn) {
var keyChar = key.value;
var overrides = layout[flags.inputType + 'Overrides'];
// Handle uppercase
if (flags.uppercase) {
keyChar = getUpperCaseValue(key);
}
// Handle override
var code;
if (overrides && overrides[keyChar]) {
keyChar = overrides[keyChar];
code = keyChar.charCodeAt(0);
} else {
code = key.keyCode || keyChar.charCodeAt(0);
}
var className = isSpecialKey(key) ? 'special-key' : '';
var ratio = key.ratio || 1;
var keyWidth = placeHolderWidth * ratio;
var dataset = [{'key': 'row', 'value': nrow}];
dataset.push({'key': 'column', 'value': ncolumn});
dataset.push({'key': 'keycode', 'value': code});
if (key.compositeKey) {
dataset.push({'key': 'compositekey', 'value': key.compositeKey});
}
content += buildKey(keyChar, className, keyWidth + 'px',
dataset, key.altNote);
}));
content += '</div>';
}));
// Append empty accent char menu and key highlight into content HTML
content += '<span id="keyboard-accent-char-menu-out">' +
'<span id="keyboard-accent-char-menu"></span></span>';
content += '<span id="keyboard-key-highlight"></span>';
this.ime.innerHTML = content;
this.menu = document.getElementById('keyboard-accent-char-menu');
// Builds candidate panel
if (layout.needsCandidatePanel || flags.showCandidatePanel) {
this.ime.insertBefore(
candidatePanelToggleButtonCode(), this.ime.firstChild);
this.ime.insertBefore(candidatePanelCode(), this.ime.firstChild);
this.ime.insertBefore(pendingSymbolPanelCode(), this.ime.firstChild);
showPendingSymbols('');
showCandidates([], true);
}
resizeUI(layout);
};
var showIME = function hm_showIME() {
delete this.ime.dataset.hidden;
this.ime.classList.remove('hide');
}
var hideIME = function km_hideIME() {
this.ime.classList.add('hide');
this.ime.classList.remove('candidate-panel');
this.ime.dataset.hidden = 'true';
};
// Highlight a key
var highlightKey = function kr_updateKeyHighlight(key, alternativeKey) {
if(inputType == 'tel' && !key.classList.contains('special-key')) {
key.classList.add('highlighted-big-key');
} else {
key.classList.add('highlighted');
}
if (alternativeKey) {
var spanToReplace = key.querySelector('.visual-wrapper span');
spanToReplace.textContent = alternativeKey;
}
};
// Unhighlight a key
var unHighlightKey = function kr_unHighlightKey(key) {
if(key.classList.contains('highlighted')) {
key.classList.remove('highlighted');
} else {
key.classList.remove('highlighted-big-key');
}
};
// Show pending symbols with highlight (selection) if provided
var showPendingSymbols = function km_showPendingSymbols(symbols,
highlightStart,
highlightEnd,
highlightState) {
var HIGHLIGHT_COLOR_TABLE = {
'red': 'keyboard-pending-symbols-highlight-red',
'green': 'keyboard-pending-symbols-highlight-green',
'blue': 'keyboard-pending-symbols-highlight-blue'
};
// TODO: Save the element
var pendingSymbolPanel =
document.getElementById('keyboard-pending-symbol-panel');
if (pendingSymbolPanel) {
if (typeof highlightStart === 'undefined' ||
typeof highlightEnd === 'undefined' ||
typeof highlightState === 'undefined') {
pendingSymbolPanel.textContent = symbols;
return;
}
pendingSymbolPanel.innerHTML = "<span class='" +
HIGHLIGHT_COLOR_TABLE[highlightState] +
"'>" +
symbols.slice(
highlightStart, highlightEnd) +
'</span>' +
symbols.substr(highlightEnd);
}
};
// Show candidates
// Each candidate is a string or an array of two strings
var showCandidates = function(candidates, noWindowHeightUpdate) {
var ime = document.getElementById('keyboard');
// TODO: Save the element
var candidatePanel = document.getElementById('keyboard-candidate-panel');
var isFullView = ime.classList.contains('full-candidate-panel');
if (candidatePanel) {
candidatePanel.innerHTML = '';
candidatePanel.scrollTop = candidatePanel.scrollLeft = 0;
// If there were too many candidate
delete candidatePanel.dataset.truncated;
if (candidates.length > 74) {
candidates = candidates.slice(0, 74);
candidatePanel.dataset.truncated = true;
}
candidates.forEach(function buildCandidateEntry(candidate) {
var span = document.createElement('span');
span.dataset.selection = true;
if (typeof candidate === 'string') {
span.dataset.data = span.textContent = candidate;
}
else {
span.dataset.data = candidate[1];
span.textContent = candidate[0];
}
candidatePanel.appendChild(span);
});
}
};
// Show keyboard alternatives
var showKeyboardAlternatives = function(key, keyboards, current, switchCode) {
var dataset, className, content = '';
var menu = this.menu;
var cssWidth = key.style.width;
menu.classList.add('kbr-menu-lang');
key.classList.add('kbr-menu-on');
var alreadyAdded = {};
for (var i = 0, kbr; kbr = keyboards[i]; i += 1) {
if (alreadyAdded[kbr])
continue;
className = 'keyboard-key';
if (kbr === current)
className += ' kbr-key-hold';
dataset = [
{key: 'keyboard', value: kbr},
{key: 'keycode', value: switchCode}
];
content += buildKey(
Keyboards[kbr].menuLabel,
className, cssWidth + 'px',
dataset
);
alreadyAdded[kbr] = true;
}
menu.innerHTML = content;
// Replace with the container
_altContainer = document.createElement('div');
_altContainer.style.display = 'inline-block';
_altContainer.style.width = key.style.width;
_altContainer.innerHTML = key.innerHTML;
_altContainer.className = key.className;
_menuKey = key;
key.parentNode.replaceChild(_altContainer, key);
_altContainer
.querySelectorAll('.visual-wrapper > span')[0]
.appendChild(menu);
menu.style.display = 'block';
};
// Show char alternatives.
var showAlternativesCharMenu = function(key, altChars) {
var content = '';
var left = (window.innerWidth / 2 > key.offsetLeft);
// Place the menu to the left
if (left) {
this.menu.classList.add('kbr-menu-left');
// Place menu on the right and reverse key order
} else {
this.menu.classList.add('kbr-menu-right');
altChars = altChars.reverse();
}
// How wide (in characters) is the key that we're displaying
// these alternatives for?
var keycharwidth = key.dataset.compositeKey ?
key.dataset.compositeKey.length :
1;
// Build a key for each alternative
altChars.forEach(function(alt) {
var dataset = alt.length == 1 ?
[{'key': 'keycode', 'value': alt.charCodeAt(0)}] :
[{'key': 'compositekey', 'value': alt}];
// Make each of these alternative keys 75% as wide as the key that
// it is an alternative for, but adjust for the relative number of
// characters in the original and the alternative
var width = 0.75 * key.offsetWidth / keycharwidth * alt.length;
// If there is only one alternative, then display it at least as
// wide as the original key.
if (altChars.length === 1)
width = Math.max(width, key.offsetWidth);
content += buildKey(alt, '', width + 'px', dataset);
});
this.menu.innerHTML = content;
// Replace with the container
_altContainer = document.createElement('div');
_altContainer.style.display = 'inline-block';
_altContainer.style.width = key.style.width;
_altContainer.innerHTML = key.innerHTML;
if(key.classList.contains("highlighted-big-key")) {
key.classList.remove("highlighted-big-key");
key.classList.add("highlighted");
}
_altContainer.className = key.className;
_altContainer.classList.add('kbr-menu-on');
_menuKey = key;
key.parentNode.replaceChild(_altContainer, key);
// Adjust menu style
_altContainer
.querySelectorAll('.visual-wrapper > span')[0]
.appendChild(this.menu);
this.menu.style.display = 'block';
// Adjust offset when alternatives menu overflows
var alternativesLeft = getWindowLeft(this.menu);
var alternativesRight = alternativesLeft + this.menu.offsetWidth;
// It overflows on the right
if (left && alternativesRight > window.innerWidth) {
console.log('overflowing right');
var offset = window.innerWidth - alternativesRight;
console.log(offset);
this.menu.style.left = offset + 'px';
// It overflows on the left
} else if (!left && alternativesLeft < 0) {
console.log('overflowing left');
var offset = alternativesLeft;
console.log(offset);
this.menu.style.right = offset + 'px';
}
};
// Hide the alternative menu
var hideAlternativesCharMenu = function km_hideAlternativesCharMenu() {
this.menu = document.getElementById('keyboard-accent-char-menu');
this.menu.innerHTML = '';
this.menu.className = '';
this.menu.style.display = 'none';
if (_altContainer)
_altContainer.parentNode.replaceChild(_menuKey, _altContainer);
this.menu.style.left = '';
this.menu.style.right = '';
};
var _keyArray = []; // To calculate proximity info for predictive text
// Recalculate dimensions for the current render
var resizeUI = function(layout) {
var changeScale, scale;
// Font size recalc
var ime = document.getElementById('keyboard');
if (window.innerWidth <= window.innerHeight) {
changeScale = window.innerWidth / 32;
document.documentElement.style.fontSize = changeScale + 'px';
ime.classList.remove('landscape');
ime.classList.add('portrait');
} else {
changeScale = window.innerWidth / 64;
document.documentElement.style.fontSize = changeScale + 'px';
ime.classList.remove('portrait');
ime.classList.add('landscape');
}
_keyArray = [];
// Width calc
if (layout) {
layoutWidth = layout.width || 10;
var totalWidth = document.getElementById('keyboard').clientWidth;
var placeHolderWidth = totalWidth / layoutWidth;
var ratio, keys, rows = document.querySelectorAll('.keyboard-row');
for (var r = 0, row; row = rows[r]; r += 1) {
keys = row.childNodes;
for (var k = 0, key; key = keys[k]; k += 1) {
ratio = layout.keys[r][k].ratio || 1;
key.style.width = (placeHolderWidth * ratio) + 'px';
// to get the visual width/height of the key
// for better proximity info
var visualKey = key.querySelector('.visual-wrapper');
_keyArray.push({
code: key.dataset.keycode | 0,
x: visualKey.offsetLeft,
y: visualKey.offsetTop,
width: visualKey.clientWidth,
height: visualKey.clientHeight
});
}
}
}
};
//
// Private Methods
//
//*
// Method that generates the HTML markup for each key
// @label: String inside the key
// @className: String representing a className to be added to the key
// @width: Int to be applied as moz-box-flex
// @dataset: Array of Hash with every { 'key': KEY, 'value': VALUE}
// to be applied as dataset
//*
var pendingSymbolPanelCode = function() {
var pendingSymbolPanel = document.createElement('div');
pendingSymbolPanel.id = 'keyboard-pending-symbol-panel';
return pendingSymbolPanel;
};
var candidatePanelCode = function() {
var candidatePanel = document.createElement('div');
candidatePanel.id = 'keyboard-candidate-panel';
if (inputMethodName)
candidatePanel.classList.add(inputMethodName);
return candidatePanel;
};
var candidatePanelToggleButtonCode = function() {
var toggleButton = document.createElement('span');
toggleButton.innerHTML = '⇪';
toggleButton.id = 'keyboard-candidate-panel-toggle-button';
if (inputMethodName)
toggleButton.classList.add(inputMethodName);
toggleButton.dataset.keycode = -4;
return toggleButton;
};
var buildKey = function buildKey(label, className, width, dataset, altNote) {
var altNoteHTML = '';
if (altNote) {
altNoteHTML = '<div class="alt-note">' + altNote + '</div>';
}
var content = '<button class="keyboard-key ' + className + '"';
dataset.forEach(function(data) {
content += ' data-' + data.key + '="' + data.value + '" ';
});
content += ' style="width: ' + width + '"';
content += '><span class="visual-wrapper"><span>' +
label + '</span>' + altNoteHTML + '</span></button>';
return content;
};
var getWidth = function getWidth() {
if (!this.ime)
return 0;
return this.ime.clientWidth;
};
var getHeight = function getHeight() {
if (!this.ime)
return 0;
return this.ime.clientHeight;
};
var getKeyArray = function getKeyArray() {
return _keyArray;
};
var getKeyWidth = function getKeyWidth() {
if (!this.ime)
return 0;
return Math.ceil(this.ime.clientWidth / layoutWidth);
};
var getKeyHeight = function getKeyHeight() {
if (!this.ime)
return 0;
this.ime.clientHeight;
var rows = document.querySelectorAll('.keyboard-row');
var rowCount = rows.length || 3;
return Math.ceil(this.ime.clientHeight / rowCount);
};
// Exposing pattern
return {
'init': init,
'setInputMethodName': setInputMethodName,
'draw': draw,
'ime': ime,
'hideIME': hideIME,
'showIME': showIME,
'highlightKey': highlightKey,
'unHighlightKey': unHighlightKey,
'showAlternativesCharMenu': showAlternativesCharMenu,
'showKeyboardAlternatives': showKeyboardAlternatives,
'hideAlternativesCharMenu': hideAlternativesCharMenu,
'setUpperCaseLock': setUpperCaseLock,
'resizeUI': resizeUI,
'showCandidates': showCandidates,
'showPendingSymbols': showPendingSymbols,
'getWidth': getWidth,
'getHeight': getHeight,
'getKeyArray': getKeyArray,
'getKeyWidth': getKeyWidth,
'getKeyHeight': getKeyHeight
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment