receiver.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /**
  2. * @fileOverview
  3. *
  4. * 键盘事件接收/分发器
  5. *
  6. * @author: techird
  7. * @copyright: Baidu FEX, 2014
  8. */
  9. define(function(require, exports, module) {
  10. var key = require('../tool/key');
  11. var hotbox = require('hotbox');
  12. function ReceiverRuntime() {
  13. var fsm = this.fsm;
  14. var minder = this.minder;
  15. var me = this;
  16. // 接收事件的 div
  17. var element = document.createElement('div');
  18. element.contentEditable = true;
  19. /**
  20. * @Desc: 增加tabindex属性使得element的contenteditable不管是trur还是false都能有focus和blur事件
  21. * @Editor: Naixor
  22. * @Date: 2015.09.14
  23. */
  24. element.setAttribute('tabindex', -1);
  25. element.classList.add('receiver');
  26. element.onkeydown = element.onkeypress = element.onkeyup = dispatchKeyEvent;
  27. element.addEventListener('compositionstart', dispatchKeyEvent);
  28. // element.addEventListener('compositionend', dispatchKeyEvent);
  29. this.container.appendChild(element);
  30. // receiver 对象
  31. var receiver = {
  32. element: element,
  33. selectAll: function() {
  34. // 保证有被选中的
  35. if (!element.innerHTML) element.innerHTML = ' ';
  36. var range = document.createRange();
  37. var selection = window.getSelection();
  38. range.selectNodeContents(element);
  39. selection.removeAllRanges();
  40. selection.addRange(range);
  41. element.focus();
  42. },
  43. /**
  44. * @Desc: 增加enable和disable方法用于解决热核态的输入法屏蔽问题
  45. * @Editor: Naixor
  46. * @Date: 2015.09.14
  47. */
  48. enable: function() {
  49. element.setAttribute("contenteditable", true);
  50. },
  51. disable: function() {
  52. element.setAttribute("contenteditable", false);
  53. },
  54. /**
  55. * @Desc: hack FF下div contenteditable的光标丢失BUG
  56. * @Editor: Naixor
  57. * @Date: 2015.10.15
  58. */
  59. fixFFCaretDisappeared: function() {
  60. element.removeAttribute("contenteditable");
  61. element.setAttribute("contenteditable", "true");
  62. element.blur();
  63. element.focus();
  64. },
  65. /**
  66. * 以此事件代替通过mouse事件来判断receiver丢失焦点的事件
  67. * @editor Naixor
  68. * @Date 2015-12-2
  69. */
  70. onblur: function (handler) {
  71. element.onblur = handler;
  72. }
  73. };
  74. receiver.selectAll();
  75. minder.on('beforemousedown', receiver.selectAll);
  76. minder.on('receiverfocus', receiver.selectAll);
  77. minder.on('readonly', function() {
  78. // 屏蔽minder的事件接受,删除receiver和hotbox
  79. minder.disable();
  80. editor.receiver.element.parentElement.removeChild(editor.receiver.element);
  81. editor.hotbox.$container.removeChild(editor.hotbox.$element);
  82. });
  83. // 侦听器,接收到的事件会派发给所有侦听器
  84. var listeners = [];
  85. // 侦听指定状态下的事件,如果不传 state,侦听所有状态
  86. receiver.listen = function(state, listener) {
  87. if (arguments.length == 1) {
  88. listener = state;
  89. state = '*';
  90. }
  91. listener.notifyState = state;
  92. listeners.push(listener);
  93. };
  94. function dispatchKeyEvent(e) {
  95. e.is = function(keyExpression) {
  96. var subs = keyExpression.split('|');
  97. for (var i = 0; i < subs.length; i++) {
  98. if (key.is(this, subs[i])) return true;
  99. }
  100. return false;
  101. };
  102. var listener, jumpState;
  103. for (var i = 0; i < listeners.length; i++) {
  104. listener = listeners[i];
  105. // 忽略不在侦听状态的侦听器
  106. if (listener.notifyState != '*' && listener.notifyState != fsm.state()) {
  107. continue;
  108. }
  109. /**
  110. *
  111. * 对于所有的侦听器,只允许一种处理方式:跳转状态。
  112. * 如果侦听器确定要跳转,则返回要跳转的状态。
  113. * 每个事件只允许一个侦听器进行状态跳转
  114. * 跳转动作由侦听器自行完成(因为可能需要在跳转时传递 reason),返回跳转结果即可。
  115. * 比如:
  116. *
  117. * ```js
  118. * receiver.listen('normal', function(e) {
  119. * if (isSomeReasonForJumpState(e)) {
  120. * return fsm.jump('newstate', e);
  121. * }
  122. * });
  123. * ```
  124. */
  125. if (listener.call(null, e)) {
  126. return;
  127. }
  128. }
  129. }
  130. this.receiver = receiver;
  131. }
  132. return module.exports = ReceiverRuntime;
  133. });