event.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. var _useCapture = false;
  2. /**
  3. DOM_VK_BACK_SPACE : 8
  4. DOM_VK_TAB : 9
  5. DOM_VK_RETURN : 13
  6. DOM_VK_SPACE : 32
  7. DOM_VK_PAGE_UP : 33
  8. DOM_VK_PAGE_DOWN : 34
  9. DOM_VK_END : 35
  10. DOM_VK_HOME : 36
  11. DOM_VK_LEFT : 37
  12. DOM_VK_UP : 38
  13. DOM_VK_RIGHT : 39
  14. DOM_VK_DOWN : 40
  15. DOM_VK_DELETE : 46
  16. DOM_VK_0 ~ DOM_VK_9 : 48 ~ 57
  17. DOM_VK_SEMICOLON : 59 (;:)
  18. DOM_VK_EQUALS : 61 (=+) (+)
  19. DOM_VK_A ~ DOM_VK_Z : 65 ~ 90
  20. DOM_VK_MULTIPLY : 106 (*)
  21. DOM_VK_SUBTRACT : 109 (-_) (-)
  22. DOM_VK_DECIMAL : 110 (.)
  23. DOM_VK_DIVIDE : 111 (/)
  24. DOM_VK_COMMA : 188 (,<)
  25. DOM_VK_PERIOD : 190 (.>)
  26. DOM_VK_SLASH : 191 (/?)
  27. DOM_VK_BACK_QUOTE : 192 (`~)
  28. DOM_VK_OPEN_BRACKET : 219 ([{)
  29. DOM_VK_BACK_SLASH : 220 (\|)
  30. DOM_VK_CLOSE_BRACKET : 221 (]})
  31. DOM_VK_QUOTE : 222 ('")
  32. */
  33. // 输入文字的键值
  34. var _INPUT_KEY_MAP = _toMap('8,9,13,32,46,48..57,59,61,65..90,106,109..111,188,190..192,219..222');
  35. // 移动光标的键值
  36. var _CURSORMOVE_KEY_MAP = _toMap('33..40');
  37. // 输入文字或移动光标的键值
  38. var _CHANGE_KEY_MAP = {};
  39. _each(_INPUT_KEY_MAP, function(key, val) {
  40. _CHANGE_KEY_MAP[key] = val;
  41. });
  42. _each(_CURSORMOVE_KEY_MAP, function(key, val) {
  43. _CHANGE_KEY_MAP[key] = val;
  44. });
  45. // add native event
  46. function _bindEvent(el, type, fn) {
  47. if (el.addEventListener){
  48. el.addEventListener(type, fn, _useCapture);
  49. } else if (el.attachEvent){
  50. el.attachEvent('on' + type, fn);
  51. }
  52. }
  53. // remove native event
  54. function _unbindEvent(el, type, fn) {
  55. if (el.removeEventListener){
  56. el.removeEventListener(type, fn, _useCapture);
  57. } else if (el.detachEvent){
  58. el.detachEvent('on' + type, fn);
  59. }
  60. }
  61. var _EVENT_PROPS = ('altKey,attrChange,attrName,bubbles,button,cancelable,charCode,clientX,clientY,ctrlKey,currentTarget,' +
  62. 'data,detail,eventPhase,fromElement,handler,keyCode,metaKey,newValue,offsetX,offsetY,originalTarget,pageX,' +
  63. 'pageY,prevValue,relatedNode,relatedTarget,screenX,screenY,shiftKey,srcElement,target,toElement,view,wheelDelta,which').split(',');
  64. // create KEvent class
  65. function KEvent(el, event) {
  66. this.init(el, event);
  67. }
  68. _extend(KEvent, {
  69. init : function(el, event) {
  70. var self = this, doc = el.ownerDocument || el.document || el;
  71. self.event = event;
  72. _each(_EVENT_PROPS, function(key, val) {
  73. self[val] = event[val];
  74. });
  75. if (!self.target) {
  76. self.target = self.srcElement || doc;
  77. }
  78. if (self.target.nodeType === 3) {
  79. self.target = self.target.parentNode;
  80. }
  81. if (!self.relatedTarget && self.fromElement) {
  82. self.relatedTarget = self.fromElement === self.target ? self.toElement : self.fromElement;
  83. }
  84. if (self.pageX == null && self.clientX != null) {
  85. var d = doc.documentElement, body = doc.body;
  86. self.pageX = self.clientX + (d && d.scrollLeft || body && body.scrollLeft || 0) - (d && d.clientLeft || body && body.clientLeft || 0);
  87. self.pageY = self.clientY + (d && d.scrollTop || body && body.scrollTop || 0) - (d && d.clientTop || body && body.clientTop || 0);
  88. }
  89. if (!self.which && ((self.charCode || self.charCode === 0) ? self.charCode : self.keyCode)) {
  90. self.which = self.charCode || self.keyCode;
  91. }
  92. if (!self.metaKey && self.ctrlKey) {
  93. self.metaKey = self.ctrlKey;
  94. }
  95. if (!self.which && self.button !== undefined) {
  96. self.which = (self.button & 1 ? 1 : (self.button & 2 ? 3 : (self.button & 4 ? 2 : 0)));
  97. }
  98. /**
  99. DOM_VK_SEMICOLON : 59 (;:)
  100. - IE,WEBKIT: 186
  101. - GECKO,OPERA : 59
  102. DOM_VK_EQUALS : 61 (=+)
  103. - IE,WEBKIT : 187
  104. - GECKO : 107
  105. - OPERA : 61
  106. DOM_VK_NUMPAD0 ~ DOM_VK_NUMPAD9 : 96 ~ 105
  107. - IE、WEBKIT,GECKO : 96 ~ 105
  108. - OPERA : 48 ~ 57
  109. DOM_VK_MULTIPLY : 106 (*)
  110. - IE、WEBKIT,GECKO : 106
  111. - OPERA : 42
  112. DOM_VK_ADD : 107 (+)
  113. - IE、WEBKIT,GECKO : 107
  114. - OPERA : 43
  115. DOM_VK_SUBTRACT : 109 (-_) (-)
  116. - IE,WEBKIT : 189, 109
  117. - GECKO : 109, 109
  118. - OPERA : 109, 45
  119. DOM_VK_DECIMAL : 110 (.)
  120. - IE、WEBKIT,GECKO : 110
  121. - OPERA : 78
  122. DOM_VK_DIVIDE : 111 (/)
  123. - IE、WEBKIT,GECKO : 111
  124. - OPERA : 47
  125. Reference:
  126. https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent
  127. http://msdn.microsoft.com/en-us/library/ms536940(v=VS.85).aspx
  128. */
  129. switch (self.which) {
  130. case 186 :
  131. self.which = 59;
  132. break;
  133. case 187 :
  134. case 107 :
  135. case 43 :
  136. self.which = 61;
  137. break;
  138. case 189 :
  139. case 45 :
  140. self.which = 109;
  141. break;
  142. case 42 :
  143. self.which = 106;
  144. break;
  145. case 47 :
  146. self.which = 111;
  147. break;
  148. case 78 :
  149. self.which = 110;
  150. break;
  151. }
  152. if (self.which >= 96 && self.which <= 105) {
  153. self.which -= 48;
  154. }
  155. },
  156. preventDefault : function() {
  157. var ev = this.event;
  158. if (ev.preventDefault) {
  159. ev.preventDefault();
  160. } else {
  161. ev.returnValue = false;
  162. }
  163. },
  164. stopPropagation : function() {
  165. var ev = this.event;
  166. if (ev.stopPropagation) {
  167. ev.stopPropagation();
  168. } else {
  169. ev.cancelBubble = true;
  170. }
  171. },
  172. stop : function() {
  173. this.preventDefault();
  174. this.stopPropagation();
  175. }
  176. });
  177. var _eventExpendo = 'kindeditor_' + _TIME, _eventId = 0, _eventData = {};
  178. function _getId(el) {
  179. return el[_eventExpendo] || null;
  180. }
  181. function _setId(el) {
  182. el[_eventExpendo] = ++_eventId;
  183. return _eventId;
  184. }
  185. function _removeId(el) {
  186. try {
  187. delete el[_eventExpendo];
  188. } catch(e) {
  189. if (el.removeAttribute) {
  190. el.removeAttribute(_eventExpendo);
  191. }
  192. }
  193. }
  194. function _bind(el, type, fn) {
  195. if (type.indexOf(',') >= 0) {
  196. _each(type.split(','), function() {
  197. _bind(el, this, fn);
  198. });
  199. return;
  200. }
  201. var id = _getId(el);
  202. if (!id) {
  203. id = _setId(el);
  204. }
  205. if (_eventData[id] === undefined) {
  206. _eventData[id] = {};
  207. }
  208. var events = _eventData[id][type];
  209. if (events && events.length > 0) {
  210. _unbindEvent(el, type, events[0]);
  211. } else {
  212. _eventData[id][type] = [];
  213. _eventData[id].el = el;
  214. }
  215. events = _eventData[id][type];
  216. if (events.length === 0) {
  217. events[0] = function(e) {
  218. var kevent = e ? new KEvent(el, e) : undefined;
  219. _each(events, function(i, event) {
  220. if (i > 0 && event) {
  221. event.call(el, kevent);
  222. }
  223. });
  224. };
  225. }
  226. if (_inArray(fn, events) < 0) {
  227. events.push(fn);
  228. }
  229. _bindEvent(el, type, events[0]);
  230. }
  231. function _unbind(el, type, fn) {
  232. if (type && type.indexOf(',') >= 0) {
  233. _each(type.split(','), function() {
  234. _unbind(el, this, fn);
  235. });
  236. return;
  237. }
  238. var id = _getId(el);
  239. if (!id) {
  240. return;
  241. }
  242. if (type === undefined) {
  243. if (id in _eventData) {
  244. _each(_eventData[id], function(key, events) {
  245. if (key != 'el' && events.length > 0) {
  246. _unbindEvent(el, key, events[0]);
  247. }
  248. });
  249. delete _eventData[id];
  250. _removeId(el);
  251. }
  252. return;
  253. }
  254. if (!_eventData[id]) {
  255. return;
  256. }
  257. var events = _eventData[id][type];
  258. if (events && events.length > 0) {
  259. if (fn === undefined) {
  260. _unbindEvent(el, type, events[0]);
  261. delete _eventData[id][type];
  262. } else {
  263. _each(events, function(i, event) {
  264. if (i > 0 && event === fn) {
  265. events.splice(i, 1);
  266. }
  267. });
  268. if (events.length == 1) {
  269. _unbindEvent(el, type, events[0]);
  270. delete _eventData[id][type];
  271. }
  272. }
  273. var count = 0;
  274. _each(_eventData[id], function() {
  275. count++;
  276. });
  277. if (count < 2) {
  278. delete _eventData[id];
  279. _removeId(el);
  280. }
  281. }
  282. }
  283. function _fire(el, type) {
  284. if (type.indexOf(',') >= 0) {
  285. _each(type.split(','), function() {
  286. _fire(el, this);
  287. });
  288. return;
  289. }
  290. var id = _getId(el);
  291. if (!id) {
  292. return;
  293. }
  294. var events = _eventData[id][type];
  295. if (_eventData[id] && events && events.length > 0) {
  296. events[0]();
  297. }
  298. }
  299. function _ctrl(el, key, fn) {
  300. var self = this;
  301. key = /^\d{2,}$/.test(key) ? key : key.toUpperCase().charCodeAt(0);
  302. _bind(el, 'keydown', function(e) {
  303. if (e.ctrlKey && e.which == key && !e.shiftKey && !e.altKey) {
  304. fn.call(el);
  305. e.stop();
  306. }
  307. });
  308. }
  309. var _readyFinished = false;
  310. function _ready(fn) {
  311. if (_readyFinished) {
  312. fn(KindEditor);
  313. return;
  314. }
  315. var loaded = false;
  316. function readyFunc() {
  317. if (!loaded) {
  318. loaded = true;
  319. fn(KindEditor);
  320. _readyFinished = true;
  321. }
  322. }
  323. function ieReadyFunc() {
  324. if (!loaded) {
  325. try {
  326. document.documentElement.doScroll('left');
  327. } catch(e) {
  328. setTimeout(ieReadyFunc, 100);
  329. return;
  330. }
  331. readyFunc();
  332. }
  333. }
  334. function ieReadyStateFunc() {
  335. if (document.readyState === 'complete') {
  336. readyFunc();
  337. }
  338. }
  339. if (document.addEventListener) {
  340. _bind(document, 'DOMContentLoaded', readyFunc);
  341. } else if (document.attachEvent) {
  342. _bind(document, 'readystatechange', ieReadyStateFunc);
  343. // 在跨域的frame里调用会报错
  344. var toplevel = false;
  345. try {
  346. toplevel = window.frameElement == null;
  347. } catch(e) {}
  348. if (document.documentElement.doScroll && toplevel) {
  349. ieReadyFunc();
  350. }
  351. }
  352. _bind(window, 'load', readyFunc);
  353. }
  354. /**
  355. Note:
  356. 发现绑定dbclick事件后移除element会有内存泄漏,以下代码也不起作用。
  357. Reference:
  358. http://isaacschlueter.com/2006/10/msie-memory-leaks/
  359. http://msdn.microsoft.com/en-us/library/bb250448.aspx
  360. */
  361. if (window.attachEvent) {
  362. window.attachEvent('onunload', function() {
  363. _each(_eventData, function(key, events) {
  364. if (events.el) {
  365. _unbind(events.el);
  366. }
  367. });
  368. });
  369. }
  370. K.ctrl = _ctrl;
  371. K.ready = _ready;