Tools.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. MWF.xApplication.MinderEditor = MWF.xApplication.MinderEditor || {};
  2. if ((!('innerText' in document.createElement('a'))) && ('getSelection' in window)) {
  3. HTMLElement.prototype.__defineGetter__('innerText', function() {
  4. var selection = window.getSelection(),
  5. ranges = [],
  6. str, i;
  7. // Save existing selections.
  8. for (i = 0; i < selection.rangeCount; i++) {
  9. ranges[i] = selection.getRangeAt(i);
  10. }
  11. // Deselect everything.
  12. selection.removeAllRanges();
  13. // Select `el` and all child nodes.
  14. // 'this' is the element .innerText got called on
  15. selection.selectAllChildren(this);
  16. // Get the string representation of the selected nodes.
  17. str = selection.toString();
  18. // Deselect everything. Again.
  19. selection.removeAllRanges();
  20. // Restore all formerly existing selections.
  21. for (i = 0; i < ranges.length; i++) {
  22. selection.addRange(ranges[i]);
  23. }
  24. // Oh look, this is what we wanted.
  25. // String representation of the element, close to as rendered.
  26. return str;
  27. });
  28. HTMLElement.prototype.__defineSetter__('innerText', function(text) {
  29. /**
  30. * @Desc: 解决FireFox节点内容删除后text为null,出现报错的问题
  31. * @Editor: Naixor
  32. * @Date: 2015.9.16
  33. */
  34. this.innerHTML = (text || '').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br>');
  35. });
  36. }
  37. (function(){
  38. var keymap = MWF.xApplication.MinderEditor.KeyMap = {
  39. 'Shift': 16,
  40. 'Control': 17,
  41. 'Alt': 18,
  42. 'CapsLock': 20,
  43. 'BackSpace': 8,
  44. 'Tab': 9,
  45. 'Enter': 13,
  46. 'Esc': 27,
  47. 'Space': 32,
  48. 'PageUp': 33,
  49. 'PageDown': 34,
  50. 'End': 35,
  51. 'Home': 36,
  52. 'Insert': 45,
  53. 'Left': 37,
  54. 'Up': 38,
  55. 'Right': 39,
  56. 'Down': 40,
  57. 'Direction': {
  58. 37: 1,
  59. 38: 1,
  60. 39: 1,
  61. 40: 1
  62. },
  63. 'Del': 46,
  64. 'NumLock': 144,
  65. 'Cmd': 91,
  66. 'CmdFF': 224,
  67. 'F1': 112,
  68. 'F2': 113,
  69. 'F3': 114,
  70. 'F4': 115,
  71. 'F5': 116,
  72. 'F6': 117,
  73. 'F7': 118,
  74. 'F8': 119,
  75. 'F9': 120,
  76. 'F10': 121,
  77. 'F11': 122,
  78. 'F12': 123,
  79. '`': 192,
  80. '=': 187,
  81. '-': 189,
  82. '/': 191,
  83. '.': 190
  84. };
  85. // 小写适配
  86. for (var key in keymap) {
  87. if (keymap.hasOwnProperty(key)) {
  88. keymap[key.toLowerCase()] = keymap[key];
  89. }
  90. }
  91. var aKeyCode = 65;
  92. var aCharCode = 'a'.charCodeAt(0);
  93. // letters
  94. 'abcdefghijklmnopqrstuvwxyz'.split('').forEach(function(letter) {
  95. keymap[letter] = aKeyCode + (letter.charCodeAt(0) - aCharCode);
  96. });
  97. // numbers
  98. var n = 9;
  99. do {
  100. keymap[n.toString()] = n + 48;
  101. } while (--n);
  102. }());
  103. MWF.xApplication.MinderEditor.Key = function(){
  104. var CTRL_MASK = 0x1000;
  105. var ALT_MASK = 0x2000;
  106. var SHIFT_MASK = 0x4000;
  107. function hash(unknown) {
  108. if (typeof(unknown) == 'string') {
  109. return hashKeyExpression(unknown);
  110. }
  111. return hashKeyEvent(unknown);
  112. }
  113. function is(a, b) {
  114. return a && b && hash(a) == hash(b);
  115. }
  116. this.hash = hash;
  117. this.is = is;
  118. function hashKeyEvent(keyEvent) {
  119. var hashCode = 0;
  120. if (keyEvent.ctrlKey || keyEvent.metaKey) {
  121. hashCode |= CTRL_MASK;
  122. }
  123. if (keyEvent.altKey) {
  124. hashCode |= ALT_MASK;
  125. }
  126. if (keyEvent.shiftKey) {
  127. hashCode |= SHIFT_MASK;
  128. }
  129. // Shift, Control, Alt KeyCode ignored.
  130. if ([16, 17, 18, 91].indexOf(keyEvent.keyCode) === -1) {
  131. /**
  132. * 解决浏览器输入法状态下对keyDown的keyCode判断不准确的问题,使用keyIdentifier,
  133. * 可以解决chrome和safari下的各种问题,其他浏览器依旧有问题,然而那并不影响我们对特
  134. * 需判断的按键进行判断(比如Space在safari输入法态下就是229,其他的就不是)
  135. * @editor Naixor
  136. * @Date 2015-12-2
  137. */
  138. if (keyEvent.keyCode === 229 && keyEvent.keyIdentifier) {
  139. return hashCode |= parseInt(keyEvent.keyIdentifier.substr(2), 16);
  140. }
  141. hashCode |= keyEvent.keyCode;
  142. }
  143. return hashCode;
  144. }
  145. function hashKeyExpression(keyExpression) {
  146. var hashCode = 0;
  147. keyExpression.toLowerCase().split(/\s*\+\s*/).forEach(function(name) {
  148. switch(name) {
  149. case 'ctrl':
  150. case 'cmd':
  151. hashCode |= CTRL_MASK;
  152. break;
  153. case 'alt':
  154. hashCode |= ALT_MASK;
  155. break;
  156. case 'shift':
  157. hashCode |= SHIFT_MASK;
  158. break;
  159. default:
  160. hashCode |= MWF.xApplication.MinderEditor.KeyMap[name];
  161. }
  162. });
  163. return hashCode;
  164. }
  165. };
  166. MWF.xApplication.MinderEditor.Format = function(template, args) {
  167. if (typeof(args) != 'object') {
  168. args = [].slice.call(arguments, 1);
  169. }
  170. return String(template).replace(/\{(\w+)\}/ig, function(match, $key) {
  171. return args[$key] || $key;
  172. });
  173. };
  174. MWF.xApplication.MinderEditor.Debug = function(flag) {
  175. function noop() {}
  176. function stringHash(str) {
  177. var hash = 0;
  178. for (var i = 0; i < str.length; i++) {
  179. hash += str.charCodeAt(i);
  180. }
  181. return hash;
  182. }
  183. var debugMode = this.flaged = window.location.search.indexOf(flag) != -1;
  184. if (debugMode) {
  185. var h = stringHash(flag) % 360;
  186. var flagStyle = MWF.xApplication.MinderEditor.Format(
  187. 'background: hsl({0}, 50%, 80%); ' +
  188. 'color: hsl({0}, 100%, 30%); ' +
  189. 'padding: 2px 3px; ' +
  190. 'margin: 1px 3px 0 0;' +
  191. 'border-radius: 2px;', h);
  192. var textStyle = 'background: none; color: black;';
  193. this.log = function() {
  194. var output = MWF.xApplication.MinderEditor.Format.apply(null, arguments);
  195. console.log(MWF.xApplication.MinderEditor.Format('%c{0}%c{1}', flag, output), flagStyle, textStyle);
  196. };
  197. } else {
  198. this.log = noop;
  199. }
  200. };
  201. MWF.xApplication.MinderEditor.JsonDiff = function( tree1, tree2 ){
  202. /*!
  203. * https://github.com/Starcounter-Jack/Fast-JSON-Patch
  204. * json-patch-duplex.js 0.5.0
  205. * (c) 2013 Joachim Wester
  206. * MIT license
  207. */
  208. var _objectKeys = (function () {
  209. if (Object.keys)
  210. return Object.keys;
  211. return function (o) {
  212. var keys = [];
  213. for (var i in o) {
  214. if (o.hasOwnProperty(i)) {
  215. keys.push(i);
  216. }
  217. }
  218. return keys;
  219. };
  220. })();
  221. function escapePathComponent(str) {
  222. if (str.indexOf('/') === -1 && str.indexOf('~') === -1)
  223. return str;
  224. return str.replace(/~/g, '~0').replace(/\//g, '~1');
  225. }
  226. function deepClone(obj) {
  227. if (typeof obj === "object") {
  228. return JSON.parse(JSON.stringify(obj));
  229. } else {
  230. return obj;
  231. }
  232. }
  233. // Dirty check if obj is different from mirror, generate patches and update mirror
  234. function _generate(mirror, obj, patches, path) {
  235. var newKeys = _objectKeys(obj);
  236. var oldKeys = _objectKeys(mirror);
  237. var changed = false;
  238. var deleted = false;
  239. for (var t = oldKeys.length - 1; t >= 0; t--) {
  240. var key = oldKeys[t];
  241. var oldVal = mirror[key];
  242. if (obj.hasOwnProperty(key)) {
  243. var newVal = obj[key];
  244. if (typeof oldVal == "object" && oldVal != null && typeof newVal == "object" && newVal != null) {
  245. _generate(oldVal, newVal, patches, path + "/" + escapePathComponent(key));
  246. } else {
  247. if (oldVal != newVal) {
  248. changed = true;
  249. patches.push({ op: "replace", path: path + "/" + escapePathComponent(key), value: deepClone(newVal) });
  250. }
  251. }
  252. } else {
  253. patches.push({ op: "remove", path: path + "/" + escapePathComponent(key) });
  254. deleted = true; // property has been deleted
  255. }
  256. }
  257. if (!deleted && newKeys.length == oldKeys.length) {
  258. return;
  259. }
  260. for (var t = 0; t < newKeys.length; t++) {
  261. var key = newKeys[t];
  262. if (!mirror.hasOwnProperty(key)) {
  263. patches.push({ op: "add", path: path + "/" + escapePathComponent(key), value: deepClone(obj[key]) });
  264. }
  265. }
  266. }
  267. //function compare(tree1, tree2) {
  268. // var patches = [];
  269. // _generate(tree1, tree2, patches, '');
  270. // return patches;
  271. //}
  272. var patches = [];
  273. _generate(tree1, tree2, patches, '');
  274. return patches;
  275. };