/*!
|
|
* ====================================================
|
|
* Hot Box UI - v1.0.15 - 2017-05-05
|
|
* https://github.com/fex-team/hotbox
|
|
* GitHub: https://github.com/fex-team/hotbox.git
|
|
* Copyright (c) 2017 Baidu FEX; Licensed BSD
|
|
* ====================================================
|
|
*/
|
|
|
|
(function () {
|
|
var _p = {
|
|
r: function(index) {
|
|
if (_p[index].inited) {
|
|
return _p[index].value;
|
|
}
|
|
if (typeof _p[index].value === "function") {
|
|
var module = {
|
|
exports: {}
|
|
}, returnValue = _p[index].value(null, module.exports, module);
|
|
_p[index].inited = true;
|
|
_p[index].value = returnValue;
|
|
if (returnValue !== undefined) {
|
|
return returnValue;
|
|
} else {
|
|
for (var key in module.exports) {
|
|
if (module.exports.hasOwnProperty(key)) {
|
|
_p[index].inited = true;
|
|
_p[index].value = module.exports;
|
|
return module.exports;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
_p[index].inited = true;
|
|
return _p[index].value;
|
|
}
|
|
}
|
|
};
|
|
|
|
//src/expose.js
|
|
_p[0] = {
|
|
value: function(require, exports, module) {
|
|
module.exports = window.HotBox = _p.r(1);
|
|
}
|
|
};
|
|
|
|
//src/hotbox.js
|
|
_p[1] = {
|
|
value: function(require, exports, module) {
|
|
var key = _p.r(2);
|
|
var KeyControl = _p.r(3);
|
|
/**** Dom Utils ****/
|
|
function createElement(name) {
|
|
return document.createElement(name);
|
|
}
|
|
function setElementAttribute(element, name, value) {
|
|
element.setAttribute(name, value);
|
|
}
|
|
function getElementAttribute(element, name) {
|
|
return element.getAttribute(name);
|
|
}
|
|
function addElementClass(element, name) {
|
|
element.classList.add(name);
|
|
}
|
|
function removeElementClass(element, name) {
|
|
element.classList.remove(name);
|
|
}
|
|
function appendChild(parent, child) {
|
|
parent.appendChild(child);
|
|
}
|
|
/*******************/
|
|
var IDLE = HotBox.STATE_IDLE = "idle";
|
|
var div = "div";
|
|
/**
|
|
* Simple Formatter
|
|
*/
|
|
function format(template, args) {
|
|
if (typeof args != "object") {
|
|
args = [].slice.apply(arguments, 1);
|
|
}
|
|
return String(template).replace(/\{(\w+)\}/g, function(match, name) {
|
|
return args[name] || match;
|
|
});
|
|
}
|
|
/**
|
|
* Hot Box Class
|
|
*/
|
|
function HotBox($container) {
|
|
if (typeof $container == "string") {
|
|
$container = document.querySelector($container);
|
|
}
|
|
if (!$container || !($container instanceof HTMLElement)) {
|
|
throw new Error("No container or not invalid container for hot box");
|
|
}
|
|
// 创建 HotBox Dom 解构
|
|
var $hotBox = createElement(div);
|
|
addElementClass($hotBox, "hotbox");
|
|
appendChild($container, $hotBox);
|
|
// 保存 Dom 解构和父容器
|
|
this.$element = $hotBox;
|
|
this.$container = $container;
|
|
// 标示是否是输入法状态
|
|
this.isIME = false;
|
|
/**
|
|
* @Desc: 增加一个browser用于判断浏览器类型,方便解决兼容性问题
|
|
* @Editor: Naixor
|
|
* @Date: 2015.09.14
|
|
*/
|
|
this.browser = {
|
|
sg: /se[\s\S]+metasr/.test(navigator.userAgent.toLowerCase())
|
|
};
|
|
/*
|
|
* added by zhangbobell
|
|
* 2015.09.22
|
|
* 增加父状态机,以解决在父 FSM 下状态控制的问题,最好的解决办法是增加一个函数队列
|
|
* 将其中的函数一起执行。//TODO
|
|
* */
|
|
this._parentFSM = {};
|
|
// 记录位置
|
|
this.position = {};
|
|
// 已定义的状态(string => HotBoxState)
|
|
var _states = {};
|
|
// 主状态(HotBoxState)
|
|
var _mainState = null;
|
|
// 当前状态(HotBoxState)
|
|
var _currentState = IDLE;
|
|
// 当前状态堆栈
|
|
var _stateStack = [];
|
|
// 实例引用
|
|
var _this = this;
|
|
var _controler;
|
|
/**
|
|
* Controller: {
|
|
* constructor(hotbox: HotBox),
|
|
* active: () => void
|
|
* }
|
|
*/
|
|
function _control(Controller) {
|
|
if (_controler) {
|
|
_controler.active();
|
|
return;
|
|
}
|
|
Controller = Controller || KeyControl;
|
|
_controler = new Controller(_this);
|
|
_controler.active();
|
|
$hotBox.onmousedown = function(e) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
};
|
|
return _this;
|
|
}
|
|
function _dispatchKey(e) {
|
|
var type = e.type.toLowerCase();
|
|
e.keyHash = key.hash(e);
|
|
e.isKey = function(keyExpression) {
|
|
if (!keyExpression) return false;
|
|
var expressions = keyExpression.split(/\s*\|\s*/);
|
|
while (expressions.length) {
|
|
if (e.keyHash == key.hash(expressions.shift())) return true;
|
|
}
|
|
return false;
|
|
};
|
|
e[type] = true;
|
|
// Boot: keyup and activeKey pressed on IDLE, active main state.
|
|
if (e.keyup && _this.activeKey && e.isKey(_this.activeKey) && _currentState == IDLE && _mainState) {
|
|
_activeState("main", {
|
|
x: $container.clientWidth / 2,
|
|
y: $container.clientHeight / 2
|
|
});
|
|
return;
|
|
}
|
|
var handleState = _currentState == IDLE ? _mainState : _currentState;
|
|
if (handleState) {
|
|
var handleResult = handleState.handleKeyEvent(e);
|
|
if (typeof _this.onkeyevent == "function") {
|
|
e.handleResult = handleResult;
|
|
_this.onkeyevent(e, handleResult);
|
|
}
|
|
return handleResult;
|
|
}
|
|
return null;
|
|
}
|
|
function _addState(name) {
|
|
if (!name) return _currentState;
|
|
if (name == IDLE) {
|
|
throw new Error("Can not define or use the `idle` state.");
|
|
}
|
|
_states[name] = _states[name] || new HotBoxState(this, name);
|
|
if (name == "main") {
|
|
_mainState = _states[name];
|
|
}
|
|
return _states[name];
|
|
}
|
|
function _activeState(name, position) {
|
|
_this.position = position;
|
|
// 回到 IDLE
|
|
if (name == IDLE) {
|
|
if (_currentState != IDLE) {
|
|
_stateStack.shift().deactive();
|
|
_stateStack = [];
|
|
}
|
|
_currentState = IDLE;
|
|
} else if (name == "back") {
|
|
if (_currentState != IDLE) {
|
|
_currentState.deactive();
|
|
_stateStack.shift();
|
|
_currentState = _stateStack[0];
|
|
if (_currentState) {
|
|
_currentState.active();
|
|
} else {
|
|
_currentState = "idle";
|
|
}
|
|
}
|
|
} else {
|
|
if (_currentState != IDLE) {
|
|
_currentState.deactive();
|
|
}
|
|
var newState = _states[name];
|
|
_stateStack.unshift(newState);
|
|
if (typeof _this.position == "function") {
|
|
position = _this.position(position);
|
|
}
|
|
newState.active(position);
|
|
_currentState = newState;
|
|
}
|
|
}
|
|
function setParentFSM(fsm) {
|
|
_this._parentFSM = fsm;
|
|
}
|
|
function getParentFSM() {
|
|
return _this._parentFSM;
|
|
}
|
|
this.control = _control;
|
|
this.state = _addState;
|
|
this.active = _activeState;
|
|
this.dispatch = _dispatchKey;
|
|
this.setParentFSM = setParentFSM;
|
|
this.getParentFSM = getParentFSM;
|
|
this.activeKey = "space";
|
|
this.actionKey = "space";
|
|
}
|
|
/**
|
|
* 表示热盒某个状态,包含这些状态需要的 Dom 对象
|
|
*/
|
|
function HotBoxState(hotBox, stateName) {
|
|
var BUTTON_SELECTED_CLASS = "selected";
|
|
var BUTTON_PRESSED_CLASS = "pressed";
|
|
var STATE_ACTIVE_CLASS = "active";
|
|
// 状态容器
|
|
var $state = createElement(div);
|
|
// 四种可见的按钮容器
|
|
var $center = createElement(div);
|
|
var $ring = createElement(div);
|
|
var $ringShape = createElement("div");
|
|
var $top = createElement(div);
|
|
var $bottom = createElement(div);
|
|
// 添加 CSS 类
|
|
addElementClass($state, "state");
|
|
addElementClass($state, stateName);
|
|
addElementClass($center, "center");
|
|
addElementClass($ring, "ring");
|
|
addElementClass($ringShape, "ring-shape");
|
|
addElementClass($top, "top");
|
|
addElementClass($bottom, "bottom");
|
|
// 摆放容器
|
|
appendChild(hotBox.$element, $state);
|
|
appendChild($state, $ringShape);
|
|
appendChild($state, $center);
|
|
appendChild($state, $ring);
|
|
appendChild($state, $top);
|
|
appendChild($state, $bottom);
|
|
// 记住状态名称
|
|
this.name = stateName;
|
|
// 五种按钮:中心,圆环,上栏,下栏,幕后
|
|
var buttons = {
|
|
center: null,
|
|
ring: [],
|
|
top: [],
|
|
bottom: [],
|
|
behind: []
|
|
};
|
|
var allButtons = [];
|
|
var selectedButton = null;
|
|
var pressedButton = null;
|
|
var stateActived = false;
|
|
// 布局,添加按钮后,标记需要布局
|
|
var needLayout = true;
|
|
function layout() {
|
|
var radius = buttons.ring.length * 15;
|
|
layoutRing(radius);
|
|
layoutTop(radius);
|
|
layoutBottom(radius);
|
|
indexPosition();
|
|
needLayout = false;
|
|
function layoutRing(radius) {
|
|
var ring = buttons.ring;
|
|
var step = 2 * Math.PI / ring.length;
|
|
if (buttons.center) {
|
|
buttons.center.indexedPosition = [ 0, 0 ];
|
|
}
|
|
$ringShape.style.marginLeft = $ringShape.style.marginTop = -radius + "px";
|
|
$ringShape.style.width = $ringShape.style.height = radius + radius + "px";
|
|
var $button, angle, x, y;
|
|
for (var i = 0; i < ring.length; i++) {
|
|
$button = ring[i].$button;
|
|
angle = step * i - Math.PI / 2;
|
|
x = radius * Math.cos(angle);
|
|
y = radius * Math.sin(angle);
|
|
ring[i].indexedPosition = [ x, y ];
|
|
$button.style.left = x + "px";
|
|
$button.style.top = y + "px";
|
|
}
|
|
}
|
|
function layoutTop(radius) {
|
|
var xOffset = -$top.clientWidth / 2;
|
|
var yOffset = -radius * 2 - $top.clientHeight / 2;
|
|
$top.style.marginLeft = xOffset + "px";
|
|
$top.style.marginTop = yOffset + "px";
|
|
buttons.top.forEach(function(topButton) {
|
|
var $button = topButton.$button;
|
|
topButton.indexedPosition = [ xOffset + $button.offsetLeft + $button.clientWidth / 2, yOffset ];
|
|
});
|
|
}
|
|
function layoutBottom(radius) {
|
|
var xOffset = -$bottom.clientWidth / 2;
|
|
var yOffset = radius * 2 - $bottom.clientHeight / 2;
|
|
$bottom.style.marginLeft = xOffset + "px";
|
|
$bottom.style.marginTop = yOffset + "px";
|
|
buttons.bottom.forEach(function(bottomButton) {
|
|
var $button = bottomButton.$button;
|
|
bottomButton.indexedPosition = [ xOffset + $button.offsetLeft + $button.clientWidth / 2, yOffset ];
|
|
});
|
|
}
|
|
function indexPosition() {
|
|
var positionedButtons = allButtons.filter(function(button) {
|
|
return button.indexedPosition;
|
|
});
|
|
positionedButtons.forEach(findNeightbour);
|
|
function findNeightbour(button) {
|
|
var neighbor = {};
|
|
var coef = 0;
|
|
var minCoef = {};
|
|
var homePosition = button.indexedPosition;
|
|
var candidatePosition, dx, dy, ds;
|
|
var possible, dir;
|
|
var abs = Math.abs;
|
|
positionedButtons.forEach(function(candidate) {
|
|
if (button == candidate) return;
|
|
candidatePosition = candidate.indexedPosition;
|
|
possible = [];
|
|
dx = candidatePosition[0] - homePosition[0];
|
|
dy = candidatePosition[1] - homePosition[1];
|
|
ds = Math.sqrt(dx * dx + dy * dy);
|
|
if (abs(dx) > 2) {
|
|
possible.push(dx > 0 ? "right" : "left");
|
|
possible.push(ds + abs(dy));
|
|
}
|
|
if (abs(dy) > 2) {
|
|
possible.push(dy > 0 ? "down" : "up");
|
|
possible.push(ds + abs(dx));
|
|
}
|
|
while (possible.length) {
|
|
dir = possible.shift();
|
|
coef = possible.shift();
|
|
if (!neighbor[dir] || coef < minCoef[dir]) {
|
|
neighbor[dir] = candidate;
|
|
minCoef[dir] = coef;
|
|
}
|
|
}
|
|
});
|
|
button.neighbor = neighbor;
|
|
}
|
|
}
|
|
}
|
|
function alwaysEnable() {
|
|
return true;
|
|
}
|
|
// 为状态创建按钮
|
|
function createButton(option) {
|
|
var $button = createElement(div);
|
|
addElementClass($button, "button");
|
|
var render = option.render || defaultButtonRender;
|
|
$button.innerHTML = render(format, option);
|
|
switch (option.position) {
|
|
case "center":
|
|
appendChild($center, $button);
|
|
break;
|
|
|
|
case "ring":
|
|
appendChild($ring, $button);
|
|
break;
|
|
|
|
case "top":
|
|
appendChild($top, $button);
|
|
break;
|
|
|
|
case "bottom":
|
|
appendChild($bottom, $button);
|
|
break;
|
|
}
|
|
return {
|
|
action: option.action,
|
|
enable: option.enable || alwaysEnable,
|
|
beforeShow: option.beforeShow,
|
|
key: option.key,
|
|
next: option.next,
|
|
label: option.label,
|
|
data: option.data || null,
|
|
$button: $button
|
|
};
|
|
}
|
|
// 默认按钮渲染
|
|
function defaultButtonRender(format, option) {
|
|
return format('<span class="label">{label}</span><span class="key">{key}</span>', {
|
|
label: option.label,
|
|
key: option.key && option.key.split("|")[0]
|
|
});
|
|
}
|
|
// 为当前状态添加按钮
|
|
this.button = function(option) {
|
|
var button = createButton(option);
|
|
if (option.position == "center") {
|
|
buttons.center = button;
|
|
} else if (buttons[option.position]) {
|
|
buttons[option.position].push(button);
|
|
}
|
|
allButtons.push(button);
|
|
needLayout = true;
|
|
};
|
|
function activeState(position) {
|
|
position = position || {
|
|
x: hotBox.$container.clientWidth / 2,
|
|
y: hotBox.$container.clientHeight / 2
|
|
};
|
|
if (position) {
|
|
$state.style.left = position.x + "px";
|
|
$state.style.top = position.y + "px";
|
|
}
|
|
allButtons.forEach(function(button) {
|
|
var $button = button.$button;
|
|
if ($button) {
|
|
$button.classList[button.enable() ? "add" : "remove"]("enabled");
|
|
}
|
|
if (button.beforeShow) {
|
|
button.beforeShow();
|
|
}
|
|
});
|
|
addElementClass($state, STATE_ACTIVE_CLASS);
|
|
if (needLayout) {
|
|
layout();
|
|
}
|
|
if (!selectedButton) {
|
|
select(buttons.center || buttons.ring[0] || buttons.top[0] || buttons.bottom[0]);
|
|
}
|
|
stateActived = true;
|
|
}
|
|
function deactiveState() {
|
|
removeElementClass($state, STATE_ACTIVE_CLASS);
|
|
select(null);
|
|
stateActived = false;
|
|
}
|
|
// 激活当前状态
|
|
this.active = activeState;
|
|
// 反激活当前状态
|
|
this.deactive = deactiveState;
|
|
function press(button) {
|
|
if (pressedButton && pressedButton.$button) {
|
|
removeElementClass(pressedButton.$button, BUTTON_PRESSED_CLASS);
|
|
}
|
|
pressedButton = button;
|
|
if (pressedButton && pressedButton.$button) {
|
|
addElementClass(pressedButton.$button, BUTTON_PRESSED_CLASS);
|
|
}
|
|
}
|
|
function select(button) {
|
|
if (selectedButton && selectedButton.$button) {
|
|
if (selectedButton.$button) {
|
|
removeElementClass(selectedButton.$button, BUTTON_SELECTED_CLASS);
|
|
}
|
|
}
|
|
selectedButton = button;
|
|
if (selectedButton && selectedButton.$button) {
|
|
addElementClass(selectedButton.$button, BUTTON_SELECTED_CLASS);
|
|
}
|
|
}
|
|
$state.onmouseup = function(e) {
|
|
if (e.button) return;
|
|
var target = e.target;
|
|
while (target && target != $state) {
|
|
if (target.classList.contains("button")) {
|
|
allButtons.forEach(function(button) {
|
|
if (button.$button == target) {
|
|
execute(button);
|
|
}
|
|
});
|
|
}
|
|
target = target.parentNode;
|
|
}
|
|
};
|
|
this.handleKeyEvent = function(e) {
|
|
var handleResult = null;
|
|
/**
|
|
* @Desc: 搜狗浏览器下esc只触发keyup,因此做兼容性处理
|
|
* @Editor: Naixor
|
|
* @Date: 2015.09.14
|
|
*/
|
|
if (hotBox.browser.sg) {
|
|
if (e.isKey("esc")) {
|
|
if (pressedButton) {
|
|
// 若存在已经按下的按钮,则取消操作
|
|
if (!e.isKey(pressedButton.key)) {
|
|
// the button is not esc
|
|
press(null);
|
|
}
|
|
} else {
|
|
hotBox.active("back", hotBox.position);
|
|
}
|
|
return "back";
|
|
}
|
|
}
|
|
if (e.keydown || hotBox.isIME && e.keyup) {
|
|
allButtons.forEach(function(button) {
|
|
if (button.enable() && e.isKey(button.key)) {
|
|
if (stateActived || hotBox.hintDeactiveMainState) {
|
|
select(button);
|
|
press(button);
|
|
handleResult = "buttonpress";
|
|
// 如果是 keyup 事件触发的,因为没有后续的按键事件,所以就直接执行
|
|
if (e.keyup) {
|
|
execute(button);
|
|
handleResult = "execute";
|
|
return handleResult;
|
|
}
|
|
} else {
|
|
execute(button);
|
|
handleResult = "execute";
|
|
}
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
if (!stateActived && hotBox.hintDeactiveMainState) {
|
|
hotBox.active(stateName, hotBox.position);
|
|
}
|
|
}
|
|
});
|
|
if (stateActived) {
|
|
if (e.isKey("esc")) {
|
|
if (pressedButton) {
|
|
// 若存在已经按下的按钮,则取消操作
|
|
if (!e.isKey(pressedButton.key)) {
|
|
// the button is not esc
|
|
press(null);
|
|
}
|
|
} else {
|
|
hotBox.active("back", hotBox.position);
|
|
}
|
|
return "back";
|
|
}
|
|
[ "up", "down", "left", "right" ].forEach(function(dir) {
|
|
if (!e.isKey(dir)) return;
|
|
if (!selectedButton) {
|
|
select(buttons.center || buttons.ring[0] || buttons.top[0] || buttons.bottom[0]);
|
|
return;
|
|
}
|
|
var neighbor = selectedButton.neighbor[dir];
|
|
while (neighbor && !neighbor.enable()) {
|
|
neighbor = neighbor.neighbor[dir];
|
|
}
|
|
if (neighbor) {
|
|
select(neighbor);
|
|
}
|
|
handleResult = "navigate";
|
|
});
|
|
// 若是由 keyup 触发的,则直接执行选中的按钮
|
|
if (e.isKey("space") && e.keyup) {
|
|
execute(selectedButton);
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
handleResult = "execute";
|
|
} else if (e.isKey("space") && selectedButton) {
|
|
press(selectedButton);
|
|
handleResult = "buttonpress";
|
|
} else if (pressedButton && pressedButton != selectedButton) {
|
|
press(null);
|
|
handleResult = "selectcancel";
|
|
}
|
|
}
|
|
} else if (e.keyup && (stateActived || !hotBox.hintDeactiveMainState)) {
|
|
if (pressedButton) {
|
|
if (e.isKey("space") && selectedButton == pressedButton || e.isKey(pressedButton.key)) {
|
|
execute(pressedButton);
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
handleResult = "execute";
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Add by zhangbobell 2015.09.06
|
|
* 增加了下面这一个判断因为 safari 下开启输入法后,所有的 keydown 的 keycode 都为 229,
|
|
* 只能以 keyup 的 keycode 进行判断
|
|
* */
|
|
hotBox.isIME = e.keyCode == 229 && e.keydown;
|
|
return handleResult;
|
|
};
|
|
function execute(button) {
|
|
if (button) {
|
|
if (!button.enable || button.enable()) {
|
|
if (button.action) button.action(button);
|
|
hotBox.active(button.next || IDLE, hotBox.position);
|
|
}
|
|
press(null);
|
|
select(null);
|
|
}
|
|
}
|
|
}
|
|
module.exports = HotBox;
|
|
}
|
|
};
|
|
|
|
//src/key.js
|
|
_p[2] = {
|
|
value: function(require, exports, module) {
|
|
var keymap = _p.r(4);
|
|
var CTRL_MASK = 4096;
|
|
var ALT_MASK = 8192;
|
|
var SHIFT_MASK = 16384;
|
|
function hash(unknown) {
|
|
if (typeof unknown == "string") {
|
|
return hashKeyExpression(unknown);
|
|
}
|
|
return hashKeyEvent(unknown);
|
|
}
|
|
function is(a, b) {
|
|
return a && b && hash(a) == hash(b);
|
|
}
|
|
exports.hash = hash;
|
|
exports.is = is;
|
|
function hashKeyEvent(keyEvent) {
|
|
var hashCode = 0;
|
|
if (keyEvent.ctrlKey || keyEvent.metaKey) {
|
|
hashCode |= CTRL_MASK;
|
|
}
|
|
if (keyEvent.altKey) {
|
|
hashCode |= ALT_MASK;
|
|
}
|
|
if (keyEvent.shiftKey) {
|
|
hashCode |= SHIFT_MASK;
|
|
}
|
|
// Shift, Control, Alt KeyCode ignored.
|
|
if ([ 16, 17, 18, 91 ].indexOf(keyEvent.keyCode) == -1) {
|
|
hashCode |= keyEvent.keyCode;
|
|
}
|
|
return hashCode;
|
|
}
|
|
function hashKeyExpression(keyExpression) {
|
|
var hashCode = 0;
|
|
keyExpression.toLowerCase().split(/\s*\+\s*/).forEach(function(name) {
|
|
switch (name) {
|
|
case "ctrl":
|
|
case "cmd":
|
|
hashCode |= CTRL_MASK;
|
|
break;
|
|
|
|
case "alt":
|
|
hashCode |= ALT_MASK;
|
|
break;
|
|
|
|
case "shift":
|
|
hashCode |= SHIFT_MASK;
|
|
break;
|
|
|
|
default:
|
|
hashCode |= keymap[name];
|
|
}
|
|
});
|
|
return hashCode;
|
|
}
|
|
}
|
|
};
|
|
|
|
//src/keycontrol.js
|
|
_p[3] = {
|
|
value: function(require, exports, module) {
|
|
var key = _p.r(2);
|
|
var FOCUS_CLASS = "hotbox-focus";
|
|
var RECEIVER_CLASS = "hotbox-key-receiver";
|
|
function KeyControl(hotbox) {
|
|
var _this = this;
|
|
var _receiver;
|
|
var _actived = true;
|
|
var _receiverIsSelfCreated = false;
|
|
var $container = hotbox.$container;
|
|
_createReceiver();
|
|
_bindReceiver();
|
|
_bindContainer();
|
|
_active();
|
|
function _createReceiver() {
|
|
_receiver = document.createElement("input");
|
|
_receiver.classList.add(RECEIVER_CLASS);
|
|
$container.appendChild(_receiver);
|
|
_receiverIsSelfCreated = true;
|
|
}
|
|
function _bindReceiver() {
|
|
_receiver.onkeyup = _handle;
|
|
_receiver.onkeypress = _handle;
|
|
_receiver.onkeydown = _handle;
|
|
_receiver.onfocus = _active;
|
|
_receiver.onblur = _deactive;
|
|
if (_receiverIsSelfCreated) {
|
|
_receiver.oninput = function(e) {
|
|
_receiver.value = null;
|
|
};
|
|
}
|
|
}
|
|
function _bindContainer() {
|
|
$container.onmousedown = function(e) {
|
|
_active();
|
|
e.preventDefault();
|
|
};
|
|
}
|
|
function _handle(keyEvent) {
|
|
if (!_actived) return;
|
|
hotbox.dispatch(keyEvent);
|
|
}
|
|
function _active() {
|
|
_receiver.select();
|
|
_receiver.focus();
|
|
_actived = true;
|
|
$container.classList.add(FOCUS_CLASS);
|
|
}
|
|
function _deactive() {
|
|
_receiver.blur();
|
|
_actived = false;
|
|
$container.classList.remove(FOCUS_CLASS);
|
|
}
|
|
this.handle = _handle;
|
|
this.active = _active;
|
|
this.deactive = _deactive;
|
|
}
|
|
module.exports = KeyControl;
|
|
}
|
|
};
|
|
|
|
//src/keymap.js
|
|
_p[4] = {
|
|
value: function(require, exports, module) {
|
|
var keymap = {
|
|
Shift: 16,
|
|
Control: 17,
|
|
Alt: 18,
|
|
CapsLock: 20,
|
|
BackSpace: 8,
|
|
Tab: 9,
|
|
Enter: 13,
|
|
Esc: 27,
|
|
Space: 32,
|
|
PageUp: 33,
|
|
PageDown: 34,
|
|
End: 35,
|
|
Home: 36,
|
|
Insert: 45,
|
|
Left: 37,
|
|
Up: 38,
|
|
Right: 39,
|
|
Down: 40,
|
|
Direction: {
|
|
37: 1,
|
|
38: 1,
|
|
39: 1,
|
|
40: 1
|
|
},
|
|
Delete: 46,
|
|
NumLock: 144,
|
|
Cmd: 91,
|
|
CmdFF: 224,
|
|
F1: 112,
|
|
F2: 113,
|
|
F3: 114,
|
|
F4: 115,
|
|
F5: 116,
|
|
F6: 117,
|
|
F7: 118,
|
|
F8: 119,
|
|
F9: 120,
|
|
F10: 121,
|
|
F11: 122,
|
|
F12: 123,
|
|
"`": 192,
|
|
"=": 187,
|
|
"-": 189,
|
|
"/": 191,
|
|
".": 190
|
|
};
|
|
// 小写适配
|
|
for (var key in keymap) {
|
|
if (keymap.hasOwnProperty(key)) {
|
|
keymap[key.toLowerCase()] = keymap[key];
|
|
}
|
|
}
|
|
var aKeyCode = 65;
|
|
var aCharCode = "a".charCodeAt(0);
|
|
// letters
|
|
"abcdefghijklmnopqrstuvwxyz".split("").forEach(function(letter) {
|
|
keymap[letter] = aKeyCode + (letter.charCodeAt(0) - aCharCode);
|
|
});
|
|
// numbers
|
|
var n = 9;
|
|
do {
|
|
keymap[n.toString()] = n + 48;
|
|
} while (n--);
|
|
module.exports = keymap;
|
|
}
|
|
};
|
|
|
|
var moduleMapping = {
|
|
expose: 0
|
|
};
|
|
|
|
function use(name) {
|
|
_p.r([ moduleMapping[name] ]);
|
|
}
|
|
use('expose');
|
|
})();
|