jumping.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. * @fileOverview
  3. *
  4. * 根据按键控制状态机的跳转
  5. *
  6. * @author: techird
  7. * @copyright: Baidu FEX, 2014
  8. */
  9. define(function(require, exports, module) {
  10. var Hotbox = require('../hotbox');
  11. // Nice: http://unixpapa.com/js/key.html
  12. function isIntendToInput(e) {
  13. if (e.ctrlKey || e.metaKey || e.altKey) return false;
  14. // a-zA-Z
  15. if (e.keyCode >= 65 && e.keyCode <= 90) return true;
  16. // 0-9 以及其上面的符号
  17. if (e.keyCode >= 48 && e.keyCode <= 57) return true;
  18. // 小键盘区域 (除回车外)
  19. if (e.keyCode != 108 && e.keyCode >= 96 && e.keyCode <= 111) return true;
  20. // 小键盘区域 (除回车外)
  21. // @yinheli from pull request
  22. if (e.keyCode != 108 && e.keyCode >= 96 && e.keyCode <= 111) return true;
  23. // 输入法
  24. if (e.keyCode == 229 || e.keyCode === 0) return true;
  25. return false;
  26. }
  27. /**
  28. * @Desc: 下方使用receiver.enable()和receiver.disable()通过
  29. * 修改div contenteditable属性的hack来解决开启热核后依然无法屏蔽浏览器输入的bug;
  30. * 特别: win下FF对于此种情况必须要先blur在focus才能解决,但是由于这样做会导致用户
  31. * 输入法状态丢失,因此对FF暂不做处理
  32. * @Editor: Naixor
  33. * @Date: 2015.09.14
  34. */
  35. function JumpingRuntime() {
  36. var fsm = this.fsm;
  37. var minder = this.minder;
  38. var receiver = this.receiver;
  39. var container = this.container;
  40. var receiverElement = receiver.element;
  41. var hotbox = this.hotbox;
  42. var compositionLock = false;
  43. // normal -> *
  44. receiver.listen('normal', function(e) {
  45. // 为了防止处理进入edit模式而丢失处理的首字母,此时receiver必须为enable
  46. receiver.enable();
  47. // normal -> hotbox
  48. if (e.is('Space')) {
  49. e.preventDefault();
  50. // safari下Space触发hotbox,然而这时Space已在receiver上留下作案痕迹,因此抹掉
  51. if (kity.Browser.safari) {
  52. receiverElement.innerHTML = '';
  53. }
  54. return fsm.jump('hotbox', 'space-trigger');
  55. }
  56. /**
  57. * check
  58. * @editor Naixor
  59. * @Date 2015-12-2
  60. */
  61. switch (e.type) {
  62. case 'keydown': {
  63. if (minder.getSelectedNode()) {
  64. if (isIntendToInput(e)) {
  65. return fsm.jump('input', 'user-input');
  66. };
  67. } else {
  68. receiverElement.innerHTML = '';
  69. }
  70. // normal -> normal shortcut
  71. fsm.jump('normal', 'shortcut-handle', e);
  72. break;
  73. }
  74. case 'keyup': {
  75. break;
  76. }
  77. default: {}
  78. }
  79. });
  80. // hotbox -> normal
  81. receiver.listen('hotbox', function(e) {
  82. receiver.disable();
  83. e.preventDefault();
  84. var handleResult = hotbox.dispatch(e);
  85. if (hotbox.state() == Hotbox.STATE_IDLE && fsm.state() == 'hotbox') {
  86. return fsm.jump('normal', 'hotbox-idle');
  87. }
  88. });
  89. // input => normal
  90. receiver.listen('input', function(e) {
  91. receiver.enable();
  92. if (e.type == 'keydown') {
  93. if (e.is('Enter')) {
  94. e.preventDefault();
  95. return fsm.jump('normal', 'input-commit');
  96. }
  97. if (e.is('Esc')) {
  98. e.preventDefault();
  99. return fsm.jump('normal', 'input-cancel');
  100. }
  101. if (e.is('Tab') || e.is('Shift + Tab')) {
  102. e.preventDefault();
  103. }
  104. } else if (e.type == 'keyup' && e.is('Esc')) {
  105. e.preventDefault();
  106. if (!compositionLock) {
  107. return fsm.jump('normal', 'input-cancel');
  108. }
  109. }
  110. else if (e.type == 'compositionstart') {
  111. compositionLock = true;
  112. }
  113. else if (e.type == 'compositionend') {
  114. setTimeout(function () {
  115. compositionLock = false;
  116. });
  117. }
  118. });
  119. //////////////////////////////////////////////
  120. /// 右键呼出热盒
  121. /// 判断的标准是:按下的位置和结束的位置一致
  122. //////////////////////////////////////////////
  123. var downX, downY;
  124. var MOUSE_RB = 2; // 右键
  125. container.addEventListener('mousedown', function(e) {
  126. if (e.button == MOUSE_RB) {
  127. e.preventDefault();
  128. }
  129. if (fsm.state() == 'hotbox') {
  130. hotbox.active(Hotbox.STATE_IDLE);
  131. fsm.jump('normal', 'blur');
  132. } else if (fsm.state() == 'normal' && e.button == MOUSE_RB) {
  133. downX = e.clientX;
  134. downY = e.clientY;
  135. }
  136. }, false);
  137. container.addEventListener('mousewheel', function(e) {
  138. if (fsm.state() == 'hotbox') {
  139. hotbox.active(Hotbox.STATE_IDLE);
  140. fsm.jump('normal', 'mousemove-blur');
  141. }
  142. }, false);
  143. container.addEventListener('contextmenu', function(e) {
  144. e.preventDefault();
  145. });
  146. container.addEventListener('mouseup', function(e) {
  147. if (fsm.state() != 'normal') {
  148. return;
  149. }
  150. if (e.button != MOUSE_RB || e.clientX != downX || e.clientY != downY) {
  151. return;
  152. }
  153. if (!minder.getSelectedNode()) {
  154. return;
  155. }
  156. fsm.jump('hotbox', 'content-menu');
  157. }, false);
  158. // 阻止热盒事件冒泡,在热盒正确执行前导致热盒关闭
  159. hotbox.$element.addEventListener('mousedown', function(e) {
  160. e.stopPropagation();
  161. });
  162. }
  163. return module.exports = JumpingRuntime;
  164. });