bee_api 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. data/bin/bee_api +84 -0
  2. data/lib/mdpreview.rb +80 -0
  3. data/lib/mdpreview/translator.rb +60 -0
  4. data/lib/mdpreview/version.rb +3 -0
  5. data/test/mdptest.rb +100 -0
  6. data/vendor/HISTORY.md +237 -0
  7. data/vendor/Jakefile.js +316 -0
  8. data/vendor/LICENSE +176 -0
  9. data/vendor/NOTICE +17 -0
  10. data/vendor/README.md +102 -0
  11. data/vendor/app/chrome/documentation.txt +12 -0
  12. data/vendor/app/chrome/manifest.json +24 -0
  13. data/vendor/app/web/ajax.js +43 -0
  14. data/vendor/app/web/app.css +292 -0
  15. data/vendor/app/web/app.js +377 -0
  16. data/vendor/app/web/beta/index.html +17 -0
  17. data/vendor/app/web/datapolicy.txt +48 -0
  18. data/vendor/app/web/doc/doc.css +60 -0
  19. data/vendor/app/web/doc/img/actions_menu.png +0 -0
  20. data/vendor/app/web/doc/img/button_actions_menu.png +0 -0
  21. data/vendor/app/web/doc/img/button_dragarea.png +0 -0
  22. data/vendor/app/web/doc/img/jsoneditor.png +0 -0
  23. data/vendor/app/web/doc/img/jsonformatter.png +0 -0
  24. data/vendor/app/web/doc/img/main_menu.png +0 -0
  25. data/vendor/app/web/doc/img/splitter.png +0 -0
  26. data/vendor/app/web/doc/index.html +201 -0
  27. data/vendor/app/web/favicon.ico +0 -0
  28. data/vendor/app/web/fileretriever.css +54 -0
  29. data/vendor/app/web/fileretriever.js +567 -0
  30. data/vendor/app/web/fileretriever.php +120 -0
  31. data/vendor/app/web/googlea47c4a0b36d11021.html +1 -0
  32. data/vendor/app/web/hash.js +133 -0
  33. data/vendor/app/web/img/description.txt +20 -0
  34. data/vendor/app/web/img/header_background.png +0 -0
  35. data/vendor/app/web/img/icon_128.png +0 -0
  36. data/vendor/app/web/img/icon_16.png +0 -0
  37. data/vendor/app/web/img/icon_gray.svg +151 -0
  38. data/vendor/app/web/img/icon_gray_16.svg +150 -0
  39. data/vendor/app/web/img/icon_orange.svg +151 -0
  40. data/vendor/app/web/img/logo.png +0 -0
  41. data/vendor/app/web/img/logo.xcf +0 -0
  42. data/vendor/app/web/img/logo_app.png +0 -0
  43. data/vendor/app/web/img/logo_app.xcf +0 -0
  44. data/vendor/app/web/index.html +191 -0
  45. data/vendor/app/web/notify.js +150 -0
  46. data/vendor/app/web/queryparams.js +71 -0
  47. data/vendor/app/web/robots.txt +0 -0
  48. data/vendor/app/web/splitter.js +179 -0
  49. data/vendor/app/web/test.html +224 -0
  50. data/vendor/component.json +33 -0
  51. data/vendor/docs/api.md +188 -0
  52. data/vendor/docs/usage.md +137 -0
  53. data/vendor/examples/01_basic_usage.html +45 -0
  54. data/vendor/examples/02_viewer.html +38 -0
  55. data/vendor/examples/03_switch_mode.html +98 -0
  56. data/vendor/examples/cur.file +1 -0
  57. data/vendor/examples/jquery.js +2 -0
  58. data/vendor/examples/meta.js +1 -0
  59. data/vendor/examples/requirejs_demo/requirejs_demo.html +19 -0
  60. data/vendor/examples/requirejs_demo/scripts/main.js +25 -0
  61. data/vendor/examples/requirejs_demo/scripts/require.js +35 -0
  62. data/vendor/img/jsoneditor-icons.png +0 -0
  63. data/vendor/jsoneditor-min.css +1 -0
  64. data/vendor/jsoneditor-min.js +34 -0
  65. data/vendor/jsoneditor.css +597 -0
  66. data/vendor/jsoneditor.js +6069 -0
  67. data/vendor/jsoneditor/css/contextmenu.css +219 -0
  68. data/vendor/jsoneditor/css/img/description.txt +13 -0
  69. data/vendor/jsoneditor/css/img/export.sh +16 -0
  70. data/vendor/jsoneditor/css/img/jsoneditor-icons.png +0 -0
  71. data/vendor/jsoneditor/css/img/jsoneditor-icons.svg +861 -0
  72. data/vendor/jsoneditor/css/jsoneditor.css +220 -0
  73. data/vendor/jsoneditor/css/menu.css +81 -0
  74. data/vendor/jsoneditor/css/searchbox.css +73 -0
  75. data/vendor/jsoneditor/js/appendnode.js +211 -0
  76. data/vendor/jsoneditor/js/contextmenu.js +440 -0
  77. data/vendor/jsoneditor/js/header.js +32 -0
  78. data/vendor/jsoneditor/js/highlighter.js +82 -0
  79. data/vendor/jsoneditor/js/history.js +218 -0
  80. data/vendor/jsoneditor/js/jsoneditor.js +206 -0
  81. data/vendor/jsoneditor/js/module.js +50 -0
  82. data/vendor/jsoneditor/js/node.js +2864 -0
  83. data/vendor/jsoneditor/js/searchbox.js +288 -0
  84. data/vendor/jsoneditor/js/texteditor.js +311 -0
  85. data/vendor/jsoneditor/js/treeeditor.js +770 -0
  86. data/vendor/jsoneditor/js/util.js +582 -0
  87. data/vendor/lib/ace/ace.js +11 -0
  88. data/vendor/lib/ace/mode-json.js +1 -0
  89. data/vendor/lib/ace/theme-jsoneditor.js +144 -0
  90. data/vendor/lib/ace/theme-textmate.js +163 -0
  91. data/vendor/lib/ace/worker-json.js +1 -0
  92. data/vendor/lib/jsonlint/README.md +62 -0
  93. data/vendor/lib/jsonlint/jsonlint.js +432 -0
  94. data/vendor/misc/screenshots/actionsmenu_640x400.png +0 -0
  95. data/vendor/misc/screenshots/codeeditor_640x400.png +0 -0
  96. data/vendor/misc/screenshots/description.json +17 -0
  97. data/vendor/misc/screenshots/jsoneditoronline.png +0 -0
  98. data/vendor/misc/screenshots/jsoneditoronline_640x400.png +0 -0
  99. data/vendor/misc/screenshots/search_640x400.png +0 -0
  100. data/vendor/misc/screenshots/small_tile.xcf +0 -0
  101. data/vendor/misc/screenshots/small_tile_440x280.png +0 -0
  102. data/vendor/misc/todo.txt +101 -0
  103. data/vendor/package.json +28 -0
  104. data/vendor/test/couchdbeditor.html +100 -0
  105. data/vendor/test/largefile.json +12605 -0
  106. data/vendor/test/test_ace.html +60 -0
  107. data/vendor/test/test_editable_div.html +449 -0
  108. metadata +154 -0
@@ -0,0 +1,582 @@
1
+ // create namespace
2
+ util = {};
3
+
4
+ // Internet Explorer 8 and older does not support Array.indexOf,
5
+ // so we define it here in that case
6
+ // http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/
7
+ if(!Array.prototype.indexOf) {
8
+ Array.prototype.indexOf = function(obj){
9
+ for(var i = 0; i < this.length; i++){
10
+ if(this[i] == obj){
11
+ return i;
12
+ }
13
+ }
14
+ return -1;
15
+ }
16
+ }
17
+
18
+ // Internet Explorer 8 and older does not support Array.forEach,
19
+ // so we define it here in that case
20
+ // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach
21
+ if (!Array.prototype.forEach) {
22
+ Array.prototype.forEach = function(fn, scope) {
23
+ for(var i = 0, len = this.length; i < len; ++i) {
24
+ fn.call(scope || this, this[i], i, this);
25
+ }
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Parse JSON using the parser built-in in the browser.
31
+ * On exception, the jsonString is validated and a detailed error is thrown.
32
+ * @param {String} jsonString
33
+ */
34
+ util.parse = function (jsonString) {
35
+ try {
36
+ return JSON.parse(jsonString);
37
+ }
38
+ catch (err) {
39
+ // try to throw a more detailed error message using validate
40
+ util.validate(jsonString);
41
+ throw err;
42
+ }
43
+ };
44
+
45
+ /**
46
+ * Validate a string containing a JSON object
47
+ * This method uses JSONLint to validate the String. If JSONLint is not
48
+ * available, the built-in JSON parser of the browser is used.
49
+ * @param {String} jsonString String with an (invalid) JSON object
50
+ * @throws Error
51
+ */
52
+ util.validate = function (jsonString) {
53
+ if (typeof(jsonlint) != 'undefined') {
54
+ jsonlint.parse(jsonString);
55
+ }
56
+ else {
57
+ JSON.parse(jsonString);
58
+ }
59
+ };
60
+
61
+ /**
62
+ * Extend object a with the properties of object b
63
+ * @param {Object} a
64
+ * @param {Object} b
65
+ * @return {Object} a
66
+ */
67
+ util.extend = function (a, b) {
68
+ for (var prop in b) {
69
+ if (b.hasOwnProperty(prop)) {
70
+ a[prop] = b[prop];
71
+ }
72
+ }
73
+ return a;
74
+ };
75
+
76
+ /**
77
+ * Remove all properties from object a
78
+ * @param {Object} a
79
+ * @return {Object} a
80
+ */
81
+ util.clear = function (a) {
82
+ for (var prop in a) {
83
+ if (a.hasOwnProperty(prop)) {
84
+ delete a[prop];
85
+ }
86
+ }
87
+ return a;
88
+ };
89
+
90
+ /**
91
+ * Output text to the console, if console is available
92
+ * @param {...*} args
93
+ */
94
+ util.log = function(args) {
95
+ if (console && typeof console.log === 'function') {
96
+ console.log.apply(console, arguments);
97
+ }
98
+ };
99
+
100
+ /**
101
+ * Test whether a text contains a url (matches when a string starts
102
+ * with 'http://*' or 'https://*' and has no whitespace characters)
103
+ * @param {String} text
104
+ */
105
+ var isUrlRegex = /^https?:\/\/\S+$/;
106
+ util.isUrl = function (text) {
107
+ return (typeof text == 'string' || text instanceof String) &&
108
+ isUrlRegex.test(text);
109
+ };
110
+
111
+ /**
112
+ * Retrieve the absolute left value of a DOM element
113
+ * @param {Element} elem A dom element, for example a div
114
+ * @return {Number} left The absolute left position of this element
115
+ * in the browser page.
116
+ */
117
+ util.getAbsoluteLeft = function (elem) {
118
+ var left = elem.offsetLeft;
119
+ var body = document.body;
120
+ var e = elem.offsetParent;
121
+ while (e != null && elem != body) {
122
+ left += e.offsetLeft;
123
+ left -= e.scrollLeft;
124
+ e = e.offsetParent;
125
+ }
126
+ return left;
127
+ };
128
+
129
+ /**
130
+ * Retrieve the absolute top value of a DOM element
131
+ * @param {Element} elem A dom element, for example a div
132
+ * @return {Number} top The absolute top position of this element
133
+ * in the browser page.
134
+ */
135
+ util.getAbsoluteTop = function (elem) {
136
+ var top = elem.offsetTop;
137
+ var body = document.body;
138
+ var e = elem.offsetParent;
139
+ while (e != null && e != body) {
140
+ top += e.offsetTop;
141
+ top -= e.scrollTop;
142
+ e = e.offsetParent;
143
+ }
144
+ return top;
145
+ };
146
+
147
+ /**
148
+ * Get the absolute, vertical mouse position from an event.
149
+ * @param {Event} event
150
+ * @return {Number} mouseY
151
+ */
152
+ util.getMouseY = function (event) {
153
+ var mouseY;
154
+ if ('pageY' in event) {
155
+ mouseY = event.pageY;
156
+ }
157
+ else {
158
+ // for IE8 and older
159
+ mouseY = (event.clientY + document.documentElement.scrollTop);
160
+ }
161
+
162
+ return mouseY;
163
+ };
164
+
165
+ /**
166
+ * Get the absolute, horizontal mouse position from an event.
167
+ * @param {Event} event
168
+ * @return {Number} mouseX
169
+ */
170
+ util.getMouseX = function (event) {
171
+ var mouseX;
172
+ if ('pageX' in event) {
173
+ mouseX = event.pageX;
174
+ }
175
+ else {
176
+ // for IE8 and older
177
+ mouseX = (event.clientX + document.documentElement.scrollLeft);
178
+ }
179
+
180
+ return mouseX;
181
+ };
182
+
183
+ /**
184
+ * Get the window height
185
+ * @return {Number} windowHeight
186
+ */
187
+ util.getWindowHeight = function () {
188
+ if ('innerHeight' in window) {
189
+ return window.innerHeight;
190
+ }
191
+ else {
192
+ // for IE8 and older
193
+ return Math.max(document.body.clientHeight,
194
+ document.documentElement.clientHeight);
195
+ }
196
+ };
197
+
198
+ /**
199
+ * add a className to the given elements style
200
+ * @param {Element} elem
201
+ * @param {String} className
202
+ */
203
+ util.addClassName = function(elem, className) {
204
+ var classes = elem.className.split(' ');
205
+ if (classes.indexOf(className) == -1) {
206
+ classes.push(className); // add the class to the array
207
+ elem.className = classes.join(' ');
208
+ }
209
+ };
210
+
211
+ /**
212
+ * add a className to the given elements style
213
+ * @param {Element} elem
214
+ * @param {String} className
215
+ */
216
+ util.removeClassName = function(elem, className) {
217
+ var classes = elem.className.split(' ');
218
+ var index = classes.indexOf(className);
219
+ if (index != -1) {
220
+ classes.splice(index, 1); // remove the class from the array
221
+ elem.className = classes.join(' ');
222
+ }
223
+ };
224
+
225
+ /**
226
+ * Strip the formatting from the contents of a div
227
+ * the formatting from the div itself is not stripped, only from its childs.
228
+ * @param {Element} divElement
229
+ */
230
+ util.stripFormatting = function (divElement) {
231
+ var childs = divElement.childNodes;
232
+ for (var i = 0, iMax = childs.length; i < iMax; i++) {
233
+ var child = childs[i];
234
+
235
+ // remove the style
236
+ if (child.style) {
237
+ // TODO: test if child.attributes does contain style
238
+ child.removeAttribute('style');
239
+ }
240
+
241
+ // remove all attributes
242
+ var attributes = child.attributes;
243
+ if (attributes) {
244
+ for (var j = attributes.length - 1; j >= 0; j--) {
245
+ var attribute = attributes[j];
246
+ if (attribute.specified == true) {
247
+ child.removeAttribute(attribute.name);
248
+ }
249
+ }
250
+ }
251
+
252
+ // recursively strip childs
253
+ util.stripFormatting(child);
254
+ }
255
+ };
256
+
257
+ /**
258
+ * Set focus to the end of an editable div
259
+ * code from Nico Burns
260
+ * http://stackoverflow.com/users/140293/nico-burns
261
+ * http://stackoverflow.com/questions/1125292/how-to-move-cursor-to-end-of-contenteditable-entity
262
+ * @param {Element} contentEditableElement A content editable div
263
+ */
264
+ util.setEndOfContentEditable = function (contentEditableElement) {
265
+ var range, selection;
266
+ if(document.createRange) {//Firefox, Chrome, Opera, Safari, IE 9+
267
+ range = document.createRange();//Create a range (a range is a like the selection but invisible)
268
+ range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
269
+ range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
270
+ selection = window.getSelection();//get the selection object (allows you to change selection)
271
+ selection.removeAllRanges();//remove any selections already made
272
+ selection.addRange(range);//make the range you have just created the visible selection
273
+ }
274
+ else if(document.selection) {//IE 8 and lower
275
+ range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
276
+ range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
277
+ range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
278
+ range.select();//Select the range (make it the visible selection
279
+ }
280
+ };
281
+
282
+ /**
283
+ * Select all text of a content editable div.
284
+ * http://stackoverflow.com/a/3806004/1262753
285
+ * @param {Element} contentEditableElement A content editable div
286
+ */
287
+ util.selectContentEditable = function (contentEditableElement) {
288
+ if (!contentEditableElement || contentEditableElement.nodeName != 'DIV') {
289
+ return;
290
+ }
291
+
292
+ var sel, range;
293
+ if (window.getSelection && document.createRange) {
294
+ range = document.createRange();
295
+ range.selectNodeContents(contentEditableElement);
296
+ sel = window.getSelection();
297
+ sel.removeAllRanges();
298
+ sel.addRange(range);
299
+ } else if (document.body.createTextRange) {
300
+ range = document.body.createTextRange();
301
+ range.moveToElementText(contentEditableElement);
302
+ range.select();
303
+ }
304
+ };
305
+
306
+ /**
307
+ * Get text selection
308
+ * http://stackoverflow.com/questions/4687808/contenteditable-selected-text-save-and-restore
309
+ * @return {Range | TextRange | null} range
310
+ */
311
+ util.getSelection = function () {
312
+ if (window.getSelection) {
313
+ var sel = window.getSelection();
314
+ if (sel.getRangeAt && sel.rangeCount) {
315
+ return sel.getRangeAt(0);
316
+ }
317
+ } else if (document.selection && document.selection.createRange) {
318
+ return document.selection.createRange();
319
+ }
320
+ return null;
321
+ };
322
+
323
+ /**
324
+ * Set text selection
325
+ * http://stackoverflow.com/questions/4687808/contenteditable-selected-text-save-and-restore
326
+ * @param {Range | TextRange | null} range
327
+ */
328
+ util.setSelection = function (range) {
329
+ if (range) {
330
+ if (window.getSelection) {
331
+ var sel = window.getSelection();
332
+ sel.removeAllRanges();
333
+ sel.addRange(range);
334
+ } else if (document.selection && range.select) {
335
+ range.select();
336
+ }
337
+ }
338
+ };
339
+
340
+ /**
341
+ * Get selected text range
342
+ * @return {Object} params object containing parameters:
343
+ * {Number} startOffset
344
+ * {Number} endOffset
345
+ * {Element} container HTML element holding the
346
+ * selected text element
347
+ * Returns null if no text selection is found
348
+ */
349
+ util.getSelectionOffset = function () {
350
+ var range = util.getSelection();
351
+
352
+ if (range && 'startOffset' in range && 'endOffset' in range &&
353
+ range.startContainer && (range.startContainer == range.endContainer)) {
354
+ return {
355
+ startOffset: range.startOffset,
356
+ endOffset: range.endOffset,
357
+ container: range.startContainer.parentNode
358
+ };
359
+ }
360
+ else {
361
+ // TODO: implement getSelectionOffset for IE8
362
+ }
363
+
364
+ return null;
365
+ };
366
+
367
+ /**
368
+ * Set selected text range in given element
369
+ * @param {Object} params An object containing:
370
+ * {Element} container
371
+ * {Number} startOffset
372
+ * {Number} endOffset
373
+ */
374
+ util.setSelectionOffset = function (params) {
375
+ if (document.createRange && window.getSelection) {
376
+ var selection = window.getSelection();
377
+ if(selection) {
378
+ var range = document.createRange();
379
+ // TODO: do not suppose that the first child of the container is a textnode,
380
+ // but recursively find the textnodes
381
+ range.setStart(params.container.firstChild, params.startOffset);
382
+ range.setEnd(params.container.firstChild, params.endOffset);
383
+
384
+ util.setSelection(range);
385
+ }
386
+ }
387
+ else {
388
+ // TODO: implement setSelectionOffset for IE8
389
+ }
390
+ };
391
+
392
+ /**
393
+ * Get the inner text of an HTML element (for example a div element)
394
+ * @param {Element} element
395
+ * @param {Object} [buffer]
396
+ * @return {String} innerText
397
+ */
398
+ util.getInnerText = function (element, buffer) {
399
+ var first = (buffer == undefined);
400
+ if (first) {
401
+ buffer = {
402
+ 'text': '',
403
+ 'flush': function () {
404
+ var text = this.text;
405
+ this.text = '';
406
+ return text;
407
+ },
408
+ 'set': function (text) {
409
+ this.text = text;
410
+ }
411
+ };
412
+ }
413
+
414
+ // text node
415
+ if (element.nodeValue) {
416
+ return buffer.flush() + element.nodeValue;
417
+ }
418
+
419
+ // divs or other HTML elements
420
+ if (element.hasChildNodes()) {
421
+ var childNodes = element.childNodes;
422
+ var innerText = '';
423
+
424
+ for (var i = 0, iMax = childNodes.length; i < iMax; i++) {
425
+ var child = childNodes[i];
426
+
427
+ if (child.nodeName == 'DIV' || child.nodeName == 'P') {
428
+ var prevChild = childNodes[i - 1];
429
+ var prevName = prevChild ? prevChild.nodeName : undefined;
430
+ if (prevName && prevName != 'DIV' && prevName != 'P' && prevName != 'BR') {
431
+ innerText += '\n';
432
+ buffer.flush();
433
+ }
434
+ innerText += util.getInnerText(child, buffer);
435
+ buffer.set('\n');
436
+ }
437
+ else if (child.nodeName == 'BR') {
438
+ innerText += buffer.flush();
439
+ buffer.set('\n');
440
+ }
441
+ else {
442
+ innerText += util.getInnerText(child, buffer);
443
+ }
444
+ }
445
+
446
+ return innerText;
447
+ }
448
+ else {
449
+ if (element.nodeName == 'P' && util.getInternetExplorerVersion() != -1) {
450
+ // On Internet Explorer, a <p> with hasChildNodes()==false is
451
+ // rendered with a new line. Note that a <p> with
452
+ // hasChildNodes()==true is rendered without a new line
453
+ // Other browsers always ensure there is a <br> inside the <p>,
454
+ // and if not, the <p> does not render a new line
455
+ return buffer.flush();
456
+ }
457
+ }
458
+
459
+ // br or unknown
460
+ return '';
461
+ };
462
+
463
+ /**
464
+ * Returns the version of Internet Explorer or a -1
465
+ * (indicating the use of another browser).
466
+ * Source: http://msdn.microsoft.com/en-us/library/ms537509(v=vs.85).aspx
467
+ * @return {Number} Internet Explorer version, or -1 in case of an other browser
468
+ */
469
+ util.getInternetExplorerVersion = function() {
470
+ if (_ieVersion == -1) {
471
+ var rv = -1; // Return value assumes failure.
472
+ if (navigator.appName == 'Microsoft Internet Explorer')
473
+ {
474
+ var ua = navigator.userAgent;
475
+ var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
476
+ if (re.exec(ua) != null) {
477
+ rv = parseFloat( RegExp.$1 );
478
+ }
479
+ }
480
+
481
+ _ieVersion = rv;
482
+ }
483
+
484
+ return _ieVersion;
485
+ };
486
+
487
+ /**
488
+ * cached internet explorer version
489
+ * @type {Number}
490
+ * @private
491
+ */
492
+ var _ieVersion = -1;
493
+
494
+ /**
495
+ * Add and event listener. Works for all browsers
496
+ * @param {Element} element An html element
497
+ * @param {string} action The action, for example "click",
498
+ * without the prefix "on"
499
+ * @param {function} listener The callback function to be executed
500
+ * @param {boolean} [useCapture] false by default
501
+ * @return {function} the created event listener
502
+ */
503
+ util.addEventListener = function (element, action, listener, useCapture) {
504
+ if (element.addEventListener) {
505
+ if (useCapture === undefined)
506
+ useCapture = false;
507
+
508
+ if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
509
+ action = "DOMMouseScroll"; // For Firefox
510
+ }
511
+
512
+ element.addEventListener(action, listener, useCapture);
513
+ return listener;
514
+ } else {
515
+ // IE browsers
516
+ var f = function () {
517
+ return listener.call(element, window.event);
518
+ };
519
+ element.attachEvent("on" + action, f);
520
+ return f;
521
+ }
522
+ };
523
+
524
+ /**
525
+ * Remove an event listener from an element
526
+ * @param {Element} element An html dom element
527
+ * @param {string} action The name of the event, for example "mousedown"
528
+ * @param {function} listener The listener function
529
+ * @param {boolean} [useCapture] false by default
530
+ */
531
+ util.removeEventListener = function(element, action, listener, useCapture) {
532
+ if (element.removeEventListener) {
533
+ // non-IE browsers
534
+ if (useCapture === undefined)
535
+ useCapture = false;
536
+
537
+ if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
538
+ action = "DOMMouseScroll"; // For Firefox
539
+ }
540
+
541
+ element.removeEventListener(action, listener, useCapture);
542
+ } else {
543
+ // IE browsers
544
+ element.detachEvent("on" + action, listener);
545
+ }
546
+ };
547
+
548
+
549
+ /**
550
+ * Stop event propagation
551
+ * @param {Event} event
552
+ */
553
+ util.stopPropagation = function (event) {
554
+ if (!event) {
555
+ event = window.event;
556
+ }
557
+
558
+ if (event.stopPropagation) {
559
+ event.stopPropagation(); // non-IE browsers
560
+ }
561
+ else {
562
+ event.cancelBubble = true; // IE browsers
563
+ }
564
+ };
565
+
566
+
567
+ /**
568
+ * Cancels the event if it is cancelable, without stopping further propagation of the event.
569
+ * @param {Event} event
570
+ */
571
+ util.preventDefault = function (event) {
572
+ if (!event) {
573
+ event = window.event;
574
+ }
575
+
576
+ if (event.preventDefault) {
577
+ event.preventDefault(); // non-IE browsers
578
+ }
579
+ else {
580
+ event.returnValue = false; // IE browsers
581
+ }
582
+ };