sequenceserver 2.0.0.rc8 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sequenceserver +22 -30
  3. data/lib/sequenceserver/api_errors.rb +5 -1
  4. data/lib/sequenceserver/blast/constants.rb +1 -1
  5. data/lib/sequenceserver/blast/hit.rb +5 -16
  6. data/lib/sequenceserver/blast/job.rb +9 -18
  7. data/lib/sequenceserver/blast/report.rb +5 -3
  8. data/lib/sequenceserver/config.rb +4 -1
  9. data/lib/sequenceserver/database.rb +69 -9
  10. data/lib/sequenceserver/job.rb +1 -1
  11. data/lib/sequenceserver/makeblastdb.rb +40 -45
  12. data/lib/sequenceserver/routes.rb +4 -0
  13. data/lib/sequenceserver/version.rb +1 -1
  14. data/lib/sequenceserver.rb +15 -11
  15. data/public/config.js +143 -142
  16. data/public/css/fonts.css +23 -22
  17. data/public/css/grapher.css +598 -594
  18. data/public/css/sequenceserver.css +86 -24
  19. data/public/css/sequenceserver.min.css +2 -2
  20. data/public/js/alignment_exporter.js +14 -14
  21. data/public/js/databases_tree.js +215 -0
  22. data/public/js/download_fasta.js +1 -1
  23. data/public/js/hit.js +6 -2
  24. data/public/js/hits_overview.js +1 -1
  25. data/public/js/length_distribution.js +5 -5
  26. data/public/js/query.js +4 -7
  27. data/public/js/report.js +12 -24
  28. data/public/js/search.js +21 -2
  29. data/public/js/sidebar.js +4 -4
  30. data/public/js/svgExporter.js +12 -12
  31. data/public/js/visualisation_helpers.js +4 -5
  32. data/public/sequenceserver-report.min.js +11 -11
  33. data/public/sequenceserver-search.min.js +15 -11
  34. data/public/vendor/github/vakata/jstree@3.3.8/LICENSE-MIT +22 -0
  35. data/public/vendor/github/vakata/jstree@3.3.8/README.md +663 -0
  36. data/public/vendor/github/vakata/jstree@3.3.8/bower.json +33 -0
  37. data/public/vendor/github/vakata/jstree@3.3.8/component.json +28 -0
  38. data/public/vendor/github/vakata/jstree@3.3.8/composer.json +46 -0
  39. data/public/vendor/github/vakata/jstree@3.3.8/demo/README.md +2 -0
  40. data/public/vendor/github/vakata/jstree@3.3.8/demo/basic/index.html +146 -0
  41. data/public/vendor/github/vakata/jstree@3.3.8/demo/basic/root.json +1 -0
  42. data/public/vendor/github/vakata/jstree@3.3.8/dist/jstree.js +8612 -0
  43. data/public/vendor/github/vakata/jstree@3.3.8/dist/jstree.min.js +6 -0
  44. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/32px.png +0 -0
  45. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/40px.png +0 -0
  46. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/style.css +1102 -0
  47. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/style.min.css +1 -0
  48. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/throbber.gif +0 -0
  49. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/32px.png +0 -0
  50. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/40px.png +0 -0
  51. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/style.css +1146 -0
  52. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/style.min.css +1 -0
  53. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/throbber.gif +0 -0
  54. data/public/vendor/github/vakata/jstree@3.3.8/gruntfile.js +242 -0
  55. data/public/vendor/github/vakata/jstree@3.3.8/jstree.jquery.json +28 -0
  56. data/public/vendor/github/vakata/jstree@3.3.8/package.json +58 -0
  57. data/public/vendor/github/vakata/jstree@3.3.8/src/intro.js +14 -0
  58. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.changed.js +69 -0
  59. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.checkbox.js +976 -0
  60. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.conditionalselect.js +38 -0
  61. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.contextmenu.js +661 -0
  62. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.dnd.js +669 -0
  63. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.js +4931 -0
  64. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.massload.js +137 -0
  65. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.search.js +421 -0
  66. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.sort.js +74 -0
  67. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.state.js +138 -0
  68. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.types.js +372 -0
  69. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.unique.js +164 -0
  70. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.wholerow.js +122 -0
  71. data/public/vendor/github/vakata/jstree@3.3.8/src/misc.js +656 -0
  72. data/public/vendor/github/vakata/jstree@3.3.8/src/outro.js +1 -0
  73. data/public/vendor/github/vakata/jstree@3.3.8/src/sample.js +93 -0
  74. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/base.less +93 -0
  75. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/32px.png +0 -0
  76. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/40px.png +0 -0
  77. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/style.css +1102 -0
  78. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/style.less +22 -0
  79. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/throbber.gif +0 -0
  80. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/32px.png +0 -0
  81. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/40px.png +0 -0
  82. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/style.css +1146 -0
  83. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/style.less +50 -0
  84. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/throbber.gif +0 -0
  85. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/main.less +77 -0
  86. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/mixins.less +104 -0
  87. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/responsive.less +67 -0
  88. data/public/vendor/github/vakata/jstree@3.3.8/src/vakata-jstree.js +38 -0
  89. data/public/vendor/github/vakata/jstree@3.3.8/test/unit/index.html +16 -0
  90. data/public/vendor/github/vakata/jstree@3.3.8/test/unit/libs/qunit.css +244 -0
  91. data/public/vendor/github/vakata/jstree@3.3.8/test/unit/libs/qunit.js +2212 -0
  92. data/public/vendor/github/vakata/jstree@3.3.8/test/unit/test.js +11 -0
  93. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/desktop/index.html +44 -0
  94. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/mobile/index.html +42 -0
  95. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/screenshots/desktop/desktop.png +0 -0
  96. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/screenshots/desktop/home.png +0 -0
  97. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/screenshots/mobile/home.png +0 -0
  98. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/screenshots/mobile/mobile.png +0 -0
  99. data/public/vendor/github/vakata/jstree@3.3.8.js +3 -0
  100. data/public/vendor/system-csp-production.js +3 -3
  101. data/public/vendor/system-csp-production.js.map +1 -1
  102. data/public/vendor/system-csp-production.src.js +146 -140
  103. data/public/vendor/system-polyfills.js.map +1 -1
  104. data/public/vendor/system-polyfills.src.js +1 -0
  105. data/public/vendor/system.js +3 -3
  106. data/public/vendor/system.js.map +1 -1
  107. data/public/vendor/system.src.js +4771 -2383
  108. data/views/_options.erb +21 -0
  109. data/views/layout.erb +17 -18
  110. metadata +102 -43
  111. data/bin/chromedriver +0 -0
  112. data/bin/geckodriver +0 -0
  113. data/public/shims/form-core.js +0 -3
  114. data/public/shims/form-validation.js +0 -3
  115. data/public/shims/plugins/jquery.ui.position.js +0 -13
  116. data/public/shims/styles/shim.css +0 -1
@@ -0,0 +1,38 @@
1
+ /**
2
+ * ### Conditionalselect plugin
3
+ *
4
+ * This plugin allows defining a callback to allow or deny node selection by user input (activate node method).
5
+ */
6
+ /*globals jQuery, define, exports, require, document */
7
+ (function (factory) {
8
+ "use strict";
9
+ if (typeof define === 'function' && define.amd) {
10
+ define('jstree.conditionalselect', ['jquery','jstree'], factory);
11
+ }
12
+ else if(typeof exports === 'object') {
13
+ factory(require('jquery'), require('jstree'));
14
+ }
15
+ else {
16
+ factory(jQuery, jQuery.jstree);
17
+ }
18
+ }(function ($, jstree, undefined) {
19
+ "use strict";
20
+
21
+ if($.jstree.plugins.conditionalselect) { return; }
22
+
23
+ /**
24
+ * a callback (function) which is invoked in the instance's scope and receives two arguments - the node and the event that triggered the `activate_node` call. Returning false prevents working with the node, returning true allows invoking activate_node. Defaults to returning `true`.
25
+ * @name $.jstree.defaults.checkbox.visible
26
+ * @plugin checkbox
27
+ */
28
+ $.jstree.defaults.conditionalselect = function () { return true; };
29
+ $.jstree.plugins.conditionalselect = function (options, parent) {
30
+ // own function
31
+ this.activate_node = function (obj, e) {
32
+ if(this.settings.conditionalselect.call(this, this.get_node(obj), e)) {
33
+ return parent.activate_node.call(this, obj, e);
34
+ }
35
+ };
36
+ };
37
+
38
+ }));
@@ -0,0 +1,661 @@
1
+ /**
2
+ * ### Contextmenu plugin
3
+ *
4
+ * Shows a context menu when a node is right-clicked.
5
+ */
6
+ /*globals jQuery, define, exports, require, document */
7
+ (function (factory) {
8
+ "use strict";
9
+ if (typeof define === 'function' && define.amd) {
10
+ define('jstree.contextmenu', ['jquery','jstree'], factory);
11
+ }
12
+ else if(typeof exports === 'object') {
13
+ factory(require('jquery'), require('jstree'));
14
+ }
15
+ else {
16
+ factory(jQuery, jQuery.jstree);
17
+ }
18
+ }(function ($, jstree, undefined) {
19
+ "use strict";
20
+
21
+ if($.jstree.plugins.contextmenu) { return; }
22
+
23
+ /**
24
+ * stores all defaults for the contextmenu plugin
25
+ * @name $.jstree.defaults.contextmenu
26
+ * @plugin contextmenu
27
+ */
28
+ $.jstree.defaults.contextmenu = {
29
+ /**
30
+ * a boolean indicating if the node should be selected when the context menu is invoked on it. Defaults to `true`.
31
+ * @name $.jstree.defaults.contextmenu.select_node
32
+ * @plugin contextmenu
33
+ */
34
+ select_node : true,
35
+ /**
36
+ * a boolean indicating if the menu should be shown aligned with the node. Defaults to `true`, otherwise the mouse coordinates are used.
37
+ * @name $.jstree.defaults.contextmenu.show_at_node
38
+ * @plugin contextmenu
39
+ */
40
+ show_at_node : true,
41
+ /**
42
+ * an object of actions, or a function that accepts a node and a callback function and calls the callback function with an object of actions available for that node (you can also return the items too).
43
+ *
44
+ * Each action consists of a key (a unique name) and a value which is an object with the following properties (only label and action are required). Once a menu item is activated the `action` function will be invoked with an object containing the following keys: item - the contextmenu item definition as seen below, reference - the DOM node that was used (the tree node), element - the contextmenu DOM element, position - an object with x/y properties indicating the position of the menu.
45
+ *
46
+ * * `separator_before` - a boolean indicating if there should be a separator before this item
47
+ * * `separator_after` - a boolean indicating if there should be a separator after this item
48
+ * * `_disabled` - a boolean indicating if this action should be disabled
49
+ * * `label` - a string - the name of the action (could be a function returning a string)
50
+ * * `title` - a string - an optional tooltip for the item
51
+ * * `action` - a function to be executed if this item is chosen, the function will receive
52
+ * * `icon` - a string, can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class
53
+ * * `shortcut` - keyCode which will trigger the action if the menu is open (for example `113` for rename, which equals F2)
54
+ * * `shortcut_label` - shortcut label (like for example `F2` for rename)
55
+ * * `submenu` - an object with the same structure as $.jstree.defaults.contextmenu.items which can be used to create a submenu - each key will be rendered as a separate option in a submenu that will appear once the current item is hovered
56
+ *
57
+ * @name $.jstree.defaults.contextmenu.items
58
+ * @plugin contextmenu
59
+ */
60
+ items : function (o, cb) { // Could be an object directly
61
+ return {
62
+ "create" : {
63
+ "separator_before" : false,
64
+ "separator_after" : true,
65
+ "_disabled" : false, //(this.check("create_node", data.reference, {}, "last")),
66
+ "label" : "Create",
67
+ "action" : function (data) {
68
+ var inst = $.jstree.reference(data.reference),
69
+ obj = inst.get_node(data.reference);
70
+ inst.create_node(obj, {}, "last", function (new_node) {
71
+ try {
72
+ inst.edit(new_node);
73
+ } catch (ex) {
74
+ setTimeout(function () { inst.edit(new_node); },0);
75
+ }
76
+ });
77
+ }
78
+ },
79
+ "rename" : {
80
+ "separator_before" : false,
81
+ "separator_after" : false,
82
+ "_disabled" : false, //(this.check("rename_node", data.reference, this.get_parent(data.reference), "")),
83
+ "label" : "Rename",
84
+ /*!
85
+ "shortcut" : 113,
86
+ "shortcut_label" : 'F2',
87
+ "icon" : "glyphicon glyphicon-leaf",
88
+ */
89
+ "action" : function (data) {
90
+ var inst = $.jstree.reference(data.reference),
91
+ obj = inst.get_node(data.reference);
92
+ inst.edit(obj);
93
+ }
94
+ },
95
+ "remove" : {
96
+ "separator_before" : false,
97
+ "icon" : false,
98
+ "separator_after" : false,
99
+ "_disabled" : false, //(this.check("delete_node", data.reference, this.get_parent(data.reference), "")),
100
+ "label" : "Delete",
101
+ "action" : function (data) {
102
+ var inst = $.jstree.reference(data.reference),
103
+ obj = inst.get_node(data.reference);
104
+ if(inst.is_selected(obj)) {
105
+ inst.delete_node(inst.get_selected());
106
+ }
107
+ else {
108
+ inst.delete_node(obj);
109
+ }
110
+ }
111
+ },
112
+ "ccp" : {
113
+ "separator_before" : true,
114
+ "icon" : false,
115
+ "separator_after" : false,
116
+ "label" : "Edit",
117
+ "action" : false,
118
+ "submenu" : {
119
+ "cut" : {
120
+ "separator_before" : false,
121
+ "separator_after" : false,
122
+ "label" : "Cut",
123
+ "action" : function (data) {
124
+ var inst = $.jstree.reference(data.reference),
125
+ obj = inst.get_node(data.reference);
126
+ if(inst.is_selected(obj)) {
127
+ inst.cut(inst.get_top_selected());
128
+ }
129
+ else {
130
+ inst.cut(obj);
131
+ }
132
+ }
133
+ },
134
+ "copy" : {
135
+ "separator_before" : false,
136
+ "icon" : false,
137
+ "separator_after" : false,
138
+ "label" : "Copy",
139
+ "action" : function (data) {
140
+ var inst = $.jstree.reference(data.reference),
141
+ obj = inst.get_node(data.reference);
142
+ if(inst.is_selected(obj)) {
143
+ inst.copy(inst.get_top_selected());
144
+ }
145
+ else {
146
+ inst.copy(obj);
147
+ }
148
+ }
149
+ },
150
+ "paste" : {
151
+ "separator_before" : false,
152
+ "icon" : false,
153
+ "_disabled" : function (data) {
154
+ return !$.jstree.reference(data.reference).can_paste();
155
+ },
156
+ "separator_after" : false,
157
+ "label" : "Paste",
158
+ "action" : function (data) {
159
+ var inst = $.jstree.reference(data.reference),
160
+ obj = inst.get_node(data.reference);
161
+ inst.paste(obj);
162
+ }
163
+ }
164
+ }
165
+ }
166
+ };
167
+ }
168
+ };
169
+
170
+ $.jstree.plugins.contextmenu = function (options, parent) {
171
+ this.bind = function () {
172
+ parent.bind.call(this);
173
+
174
+ var last_ts = 0, cto = null, ex, ey;
175
+ this.element
176
+ .on("init.jstree loading.jstree ready.jstree", $.proxy(function () {
177
+ this.get_container_ul().addClass('jstree-contextmenu');
178
+ }, this))
179
+ .on("contextmenu.jstree", ".jstree-anchor", $.proxy(function (e, data) {
180
+ if (e.target.tagName.toLowerCase() === 'input') {
181
+ return;
182
+ }
183
+ e.preventDefault();
184
+ last_ts = e.ctrlKey ? +new Date() : 0;
185
+ if(data || cto) {
186
+ last_ts = (+new Date()) + 10000;
187
+ }
188
+ if(cto) {
189
+ clearTimeout(cto);
190
+ }
191
+ if(!this.is_loading(e.currentTarget)) {
192
+ this.show_contextmenu(e.currentTarget, e.pageX, e.pageY, e);
193
+ }
194
+ }, this))
195
+ .on("click.jstree", ".jstree-anchor", $.proxy(function (e) {
196
+ if(this._data.contextmenu.visible && (!last_ts || (+new Date()) - last_ts > 250)) { // work around safari & macOS ctrl+click
197
+ $.vakata.context.hide();
198
+ }
199
+ last_ts = 0;
200
+ }, this))
201
+ .on("touchstart.jstree", ".jstree-anchor", function (e) {
202
+ if(!e.originalEvent || !e.originalEvent.changedTouches || !e.originalEvent.changedTouches[0]) {
203
+ return;
204
+ }
205
+ ex = e.originalEvent.changedTouches[0].clientX;
206
+ ey = e.originalEvent.changedTouches[0].clientY;
207
+ cto = setTimeout(function () {
208
+ $(e.currentTarget).trigger('contextmenu', true);
209
+ }, 750);
210
+ })
211
+ .on('touchmove.vakata.jstree', function (e) {
212
+ if(cto && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0] && (Math.abs(ex - e.originalEvent.changedTouches[0].clientX) > 10 || Math.abs(ey - e.originalEvent.changedTouches[0].clientY) > 10)) {
213
+ clearTimeout(cto);
214
+ $.vakata.context.hide();
215
+ }
216
+ })
217
+ .on('touchend.vakata.jstree', function (e) {
218
+ if(cto) {
219
+ clearTimeout(cto);
220
+ }
221
+ });
222
+
223
+ /*!
224
+ if(!('oncontextmenu' in document.body) && ('ontouchstart' in document.body)) {
225
+ var el = null, tm = null;
226
+ this.element
227
+ .on("touchstart", ".jstree-anchor", function (e) {
228
+ el = e.currentTarget;
229
+ tm = +new Date();
230
+ $(document).one("touchend", function (e) {
231
+ e.target = document.elementFromPoint(e.originalEvent.targetTouches[0].pageX - window.pageXOffset, e.originalEvent.targetTouches[0].pageY - window.pageYOffset);
232
+ e.currentTarget = e.target;
233
+ tm = ((+(new Date())) - tm);
234
+ if(e.target === el && tm > 600 && tm < 1000) {
235
+ e.preventDefault();
236
+ $(el).trigger('contextmenu', e);
237
+ }
238
+ el = null;
239
+ tm = null;
240
+ });
241
+ });
242
+ }
243
+ */
244
+ $(document).on("context_hide.vakata.jstree", $.proxy(function (e, data) {
245
+ this._data.contextmenu.visible = false;
246
+ $(data.reference).removeClass('jstree-context');
247
+ }, this));
248
+ };
249
+ this.teardown = function () {
250
+ if(this._data.contextmenu.visible) {
251
+ $.vakata.context.hide();
252
+ }
253
+ parent.teardown.call(this);
254
+ };
255
+
256
+ /**
257
+ * prepare and show the context menu for a node
258
+ * @name show_contextmenu(obj [, x, y])
259
+ * @param {mixed} obj the node
260
+ * @param {Number} x the x-coordinate relative to the document to show the menu at
261
+ * @param {Number} y the y-coordinate relative to the document to show the menu at
262
+ * @param {Object} e the event if available that triggered the contextmenu
263
+ * @plugin contextmenu
264
+ * @trigger show_contextmenu.jstree
265
+ */
266
+ this.show_contextmenu = function (obj, x, y, e) {
267
+ obj = this.get_node(obj);
268
+ if(!obj || obj.id === $.jstree.root) { return false; }
269
+ var s = this.settings.contextmenu,
270
+ d = this.get_node(obj, true),
271
+ a = d.children(".jstree-anchor"),
272
+ o = false,
273
+ i = false;
274
+ if(s.show_at_node || x === undefined || y === undefined) {
275
+ o = a.offset();
276
+ x = o.left;
277
+ y = o.top + this._data.core.li_height;
278
+ }
279
+ if(this.settings.contextmenu.select_node && !this.is_selected(obj)) {
280
+ this.activate_node(obj, e);
281
+ }
282
+
283
+ i = s.items;
284
+ if($.isFunction(i)) {
285
+ i = i.call(this, obj, $.proxy(function (i) {
286
+ this._show_contextmenu(obj, x, y, i);
287
+ }, this));
288
+ }
289
+ if($.isPlainObject(i)) {
290
+ this._show_contextmenu(obj, x, y, i);
291
+ }
292
+ };
293
+ /**
294
+ * show the prepared context menu for a node
295
+ * @name _show_contextmenu(obj, x, y, i)
296
+ * @param {mixed} obj the node
297
+ * @param {Number} x the x-coordinate relative to the document to show the menu at
298
+ * @param {Number} y the y-coordinate relative to the document to show the menu at
299
+ * @param {Number} i the object of items to show
300
+ * @plugin contextmenu
301
+ * @trigger show_contextmenu.jstree
302
+ * @private
303
+ */
304
+ this._show_contextmenu = function (obj, x, y, i) {
305
+ var d = this.get_node(obj, true),
306
+ a = d.children(".jstree-anchor");
307
+ $(document).one("context_show.vakata.jstree", $.proxy(function (e, data) {
308
+ var cls = 'jstree-contextmenu jstree-' + this.get_theme() + '-contextmenu';
309
+ $(data.element).addClass(cls);
310
+ a.addClass('jstree-context');
311
+ }, this));
312
+ this._data.contextmenu.visible = true;
313
+ $.vakata.context.show(a, { 'x' : x, 'y' : y }, i);
314
+ /**
315
+ * triggered when the contextmenu is shown for a node
316
+ * @event
317
+ * @name show_contextmenu.jstree
318
+ * @param {Object} node the node
319
+ * @param {Number} x the x-coordinate of the menu relative to the document
320
+ * @param {Number} y the y-coordinate of the menu relative to the document
321
+ * @plugin contextmenu
322
+ */
323
+ this.trigger('show_contextmenu', { "node" : obj, "x" : x, "y" : y });
324
+ };
325
+ };
326
+
327
+ // contextmenu helper
328
+ (function ($) {
329
+ var right_to_left = false,
330
+ vakata_context = {
331
+ element : false,
332
+ reference : false,
333
+ position_x : 0,
334
+ position_y : 0,
335
+ items : [],
336
+ html : "",
337
+ is_visible : false
338
+ };
339
+
340
+ $.vakata.context = {
341
+ settings : {
342
+ hide_onmouseleave : 0,
343
+ icons : true
344
+ },
345
+ _trigger : function (event_name) {
346
+ $(document).triggerHandler("context_" + event_name + ".vakata", {
347
+ "reference" : vakata_context.reference,
348
+ "element" : vakata_context.element,
349
+ "position" : {
350
+ "x" : vakata_context.position_x,
351
+ "y" : vakata_context.position_y
352
+ }
353
+ });
354
+ },
355
+ _execute : function (i) {
356
+ i = vakata_context.items[i];
357
+ return i && (!i._disabled || ($.isFunction(i._disabled) && !i._disabled({ "item" : i, "reference" : vakata_context.reference, "element" : vakata_context.element }))) && i.action ? i.action.call(null, {
358
+ "item" : i,
359
+ "reference" : vakata_context.reference,
360
+ "element" : vakata_context.element,
361
+ "position" : {
362
+ "x" : vakata_context.position_x,
363
+ "y" : vakata_context.position_y
364
+ }
365
+ }) : false;
366
+ },
367
+ _parse : function (o, is_callback) {
368
+ if(!o) { return false; }
369
+ if(!is_callback) {
370
+ vakata_context.html = "";
371
+ vakata_context.items = [];
372
+ }
373
+ var str = "",
374
+ sep = false,
375
+ tmp;
376
+
377
+ if(is_callback) { str += "<"+"ul>"; }
378
+ $.each(o, function (i, val) {
379
+ if(!val) { return true; }
380
+ vakata_context.items.push(val);
381
+ if(!sep && val.separator_before) {
382
+ str += "<"+"li class='vakata-context-separator'><"+"a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + ">&#160;<"+"/a><"+"/li>";
383
+ }
384
+ sep = false;
385
+ str += "<"+"li class='" + (val._class || "") + (val._disabled === true || ($.isFunction(val._disabled) && val._disabled({ "item" : val, "reference" : vakata_context.reference, "element" : vakata_context.element })) ? " vakata-contextmenu-disabled " : "") + "' "+(val.shortcut?" data-shortcut='"+val.shortcut+"' ":'')+">";
386
+ str += "<"+"a href='#' rel='" + (vakata_context.items.length - 1) + "' " + (val.title ? "title='" + val.title + "'" : "") + ">";
387
+ if($.vakata.context.settings.icons) {
388
+ str += "<"+"i ";
389
+ if(val.icon) {
390
+ if(val.icon.indexOf("/") !== -1 || val.icon.indexOf(".") !== -1) { str += " style='background:url(\"" + val.icon + "\") center center no-repeat' "; }
391
+ else { str += " class='" + val.icon + "' "; }
392
+ }
393
+ str += "><"+"/i><"+"span class='vakata-contextmenu-sep'>&#160;<"+"/span>";
394
+ }
395
+ str += ($.isFunction(val.label) ? val.label({ "item" : i, "reference" : vakata_context.reference, "element" : vakata_context.element }) : val.label) + (val.shortcut?' <span class="vakata-contextmenu-shortcut vakata-contextmenu-shortcut-'+val.shortcut+'">'+ (val.shortcut_label || '') +'</span>':'') + "<"+"/a>";
396
+ if(val.submenu) {
397
+ tmp = $.vakata.context._parse(val.submenu, true);
398
+ if(tmp) { str += tmp; }
399
+ }
400
+ str += "<"+"/li>";
401
+ if(val.separator_after) {
402
+ str += "<"+"li class='vakata-context-separator'><"+"a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + ">&#160;<"+"/a><"+"/li>";
403
+ sep = true;
404
+ }
405
+ });
406
+ str = str.replace(/<li class\='vakata-context-separator'\><\/li\>$/,"");
407
+ if(is_callback) { str += "</ul>"; }
408
+ /**
409
+ * triggered on the document when the contextmenu is parsed (HTML is built)
410
+ * @event
411
+ * @plugin contextmenu
412
+ * @name context_parse.vakata
413
+ * @param {jQuery} reference the element that was right clicked
414
+ * @param {jQuery} element the DOM element of the menu itself
415
+ * @param {Object} position the x & y coordinates of the menu
416
+ */
417
+ if(!is_callback) { vakata_context.html = str; $.vakata.context._trigger("parse"); }
418
+ return str.length > 10 ? str : false;
419
+ },
420
+ _show_submenu : function (o) {
421
+ o = $(o);
422
+ if(!o.length || !o.children("ul").length) { return; }
423
+ var e = o.children("ul"),
424
+ xl = o.offset().left,
425
+ x = xl + o.outerWidth(),
426
+ y = o.offset().top,
427
+ w = e.width(),
428
+ h = e.height(),
429
+ dw = $(window).width() + $(window).scrollLeft(),
430
+ dh = $(window).height() + $(window).scrollTop();
431
+ // може да се спести е една проверка - дали няма някой от класовете вече нагоре
432
+ if(right_to_left) {
433
+ o[x - (w + 10 + o.outerWidth()) < 0 ? "addClass" : "removeClass"]("vakata-context-left");
434
+ }
435
+ else {
436
+ o[x + w > dw && xl > dw - x ? "addClass" : "removeClass"]("vakata-context-right");
437
+ }
438
+ if(y + h + 10 > dh) {
439
+ e.css("bottom","-1px");
440
+ }
441
+
442
+ //if does not fit - stick it to the side
443
+ if (o.hasClass('vakata-context-right')) {
444
+ if (xl < w) {
445
+ e.css("margin-right", xl - w);
446
+ }
447
+ } else {
448
+ if (dw - x < w) {
449
+ e.css("margin-left", dw - x - w);
450
+ }
451
+ }
452
+
453
+ e.show();
454
+ },
455
+ show : function (reference, position, data) {
456
+ var o, e, x, y, w, h, dw, dh, cond = true;
457
+ if(vakata_context.element && vakata_context.element.length) {
458
+ vakata_context.element.width('');
459
+ }
460
+ switch(cond) {
461
+ case (!position && !reference):
462
+ return false;
463
+ case (!!position && !!reference):
464
+ vakata_context.reference = reference;
465
+ vakata_context.position_x = position.x;
466
+ vakata_context.position_y = position.y;
467
+ break;
468
+ case (!position && !!reference):
469
+ vakata_context.reference = reference;
470
+ o = reference.offset();
471
+ vakata_context.position_x = o.left + reference.outerHeight();
472
+ vakata_context.position_y = o.top;
473
+ break;
474
+ case (!!position && !reference):
475
+ vakata_context.position_x = position.x;
476
+ vakata_context.position_y = position.y;
477
+ break;
478
+ }
479
+ if(!!reference && !data && $(reference).data('vakata_contextmenu')) {
480
+ data = $(reference).data('vakata_contextmenu');
481
+ }
482
+ if($.vakata.context._parse(data)) {
483
+ vakata_context.element.html(vakata_context.html);
484
+ }
485
+ if(vakata_context.items.length) {
486
+ vakata_context.element.appendTo(document.body);
487
+ e = vakata_context.element;
488
+ x = vakata_context.position_x;
489
+ y = vakata_context.position_y;
490
+ w = e.width();
491
+ h = e.height();
492
+ dw = $(window).width() + $(window).scrollLeft();
493
+ dh = $(window).height() + $(window).scrollTop();
494
+ if(right_to_left) {
495
+ x -= (e.outerWidth() - $(reference).outerWidth());
496
+ if(x < $(window).scrollLeft() + 20) {
497
+ x = $(window).scrollLeft() + 20;
498
+ }
499
+ }
500
+ if(x + w + 20 > dw) {
501
+ x = dw - (w + 20);
502
+ }
503
+ if(y + h + 20 > dh) {
504
+ y = dh - (h + 20);
505
+ }
506
+
507
+ vakata_context.element
508
+ .css({ "left" : x, "top" : y })
509
+ .show()
510
+ .find('a').first().focus().parent().addClass("vakata-context-hover");
511
+ vakata_context.is_visible = true;
512
+ /**
513
+ * triggered on the document when the contextmenu is shown
514
+ * @event
515
+ * @plugin contextmenu
516
+ * @name context_show.vakata
517
+ * @param {jQuery} reference the element that was right clicked
518
+ * @param {jQuery} element the DOM element of the menu itself
519
+ * @param {Object} position the x & y coordinates of the menu
520
+ */
521
+ $.vakata.context._trigger("show");
522
+ }
523
+ },
524
+ hide : function () {
525
+ if(vakata_context.is_visible) {
526
+ vakata_context.element.hide().find("ul").hide().end().find(':focus').blur().end().detach();
527
+ vakata_context.is_visible = false;
528
+ /**
529
+ * triggered on the document when the contextmenu is hidden
530
+ * @event
531
+ * @plugin contextmenu
532
+ * @name context_hide.vakata
533
+ * @param {jQuery} reference the element that was right clicked
534
+ * @param {jQuery} element the DOM element of the menu itself
535
+ * @param {Object} position the x & y coordinates of the menu
536
+ */
537
+ $.vakata.context._trigger("hide");
538
+ }
539
+ }
540
+ };
541
+ $(function () {
542
+ right_to_left = $(document.body).css("direction") === "rtl";
543
+ var to = false;
544
+
545
+ vakata_context.element = $("<ul class='vakata-context'></ul>");
546
+ vakata_context.element
547
+ .on("mouseenter", "li", function (e) {
548
+ e.stopImmediatePropagation();
549
+
550
+ if($.contains(this, e.relatedTarget)) {
551
+ // премахнато заради delegate mouseleave по-долу
552
+ // $(this).find(".vakata-context-hover").removeClass("vakata-context-hover");
553
+ return;
554
+ }
555
+
556
+ if(to) { clearTimeout(to); }
557
+ vakata_context.element.find(".vakata-context-hover").removeClass("vakata-context-hover").end();
558
+
559
+ $(this)
560
+ .siblings().find("ul").hide().end().end()
561
+ .parentsUntil(".vakata-context", "li").addBack().addClass("vakata-context-hover");
562
+ $.vakata.context._show_submenu(this);
563
+ })
564
+ // тестово - дали не натоварва?
565
+ .on("mouseleave", "li", function (e) {
566
+ if($.contains(this, e.relatedTarget)) { return; }
567
+ $(this).find(".vakata-context-hover").addBack().removeClass("vakata-context-hover");
568
+ })
569
+ .on("mouseleave", function (e) {
570
+ $(this).find(".vakata-context-hover").removeClass("vakata-context-hover");
571
+ if($.vakata.context.settings.hide_onmouseleave) {
572
+ to = setTimeout(
573
+ (function (t) {
574
+ return function () { $.vakata.context.hide(); };
575
+ }(this)), $.vakata.context.settings.hide_onmouseleave);
576
+ }
577
+ })
578
+ .on("click", "a", function (e) {
579
+ e.preventDefault();
580
+ //})
581
+ //.on("mouseup", "a", function (e) {
582
+ if(!$(this).blur().parent().hasClass("vakata-context-disabled") && $.vakata.context._execute($(this).attr("rel")) !== false) {
583
+ $.vakata.context.hide();
584
+ }
585
+ })
586
+ .on('keydown', 'a', function (e) {
587
+ var o = null;
588
+ switch(e.which) {
589
+ case 13:
590
+ case 32:
591
+ e.type = "click";
592
+ e.preventDefault();
593
+ $(e.currentTarget).trigger(e);
594
+ break;
595
+ case 37:
596
+ if(vakata_context.is_visible) {
597
+ vakata_context.element.find(".vakata-context-hover").last().closest("li").first().find("ul").hide().find(".vakata-context-hover").removeClass("vakata-context-hover").end().end().children('a').focus();
598
+ e.stopImmediatePropagation();
599
+ e.preventDefault();
600
+ }
601
+ break;
602
+ case 38:
603
+ if(vakata_context.is_visible) {
604
+ o = vakata_context.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").prevAll("li:not(.vakata-context-separator)").first();
605
+ if(!o.length) { o = vakata_context.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").last(); }
606
+ o.addClass("vakata-context-hover").children('a').focus();
607
+ e.stopImmediatePropagation();
608
+ e.preventDefault();
609
+ }
610
+ break;
611
+ case 39:
612
+ if(vakata_context.is_visible) {
613
+ vakata_context.element.find(".vakata-context-hover").last().children("ul").show().children("li:not(.vakata-context-separator)").removeClass("vakata-context-hover").first().addClass("vakata-context-hover").children('a').focus();
614
+ e.stopImmediatePropagation();
615
+ e.preventDefault();
616
+ }
617
+ break;
618
+ case 40:
619
+ if(vakata_context.is_visible) {
620
+ o = vakata_context.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").nextAll("li:not(.vakata-context-separator)").first();
621
+ if(!o.length) { o = vakata_context.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").first(); }
622
+ o.addClass("vakata-context-hover").children('a').focus();
623
+ e.stopImmediatePropagation();
624
+ e.preventDefault();
625
+ }
626
+ break;
627
+ case 27:
628
+ $.vakata.context.hide();
629
+ e.preventDefault();
630
+ break;
631
+ default:
632
+ //console.log(e.which);
633
+ break;
634
+ }
635
+ })
636
+ .on('keydown', function (e) {
637
+ e.preventDefault();
638
+ var a = vakata_context.element.find('.vakata-contextmenu-shortcut-' + e.which).parent();
639
+ if(a.parent().not('.vakata-context-disabled')) {
640
+ a.click();
641
+ }
642
+ });
643
+
644
+ $(document)
645
+ .on("mousedown.vakata.jstree", function (e) {
646
+ if(vakata_context.is_visible && vakata_context.element[0] !== e.target && !$.contains(vakata_context.element[0], e.target)) {
647
+ $.vakata.context.hide();
648
+ }
649
+ })
650
+ .on("context_show.vakata.jstree", function (e, data) {
651
+ vakata_context.element.find("li:has(ul)").children("a").addClass("vakata-context-parent");
652
+ if(right_to_left) {
653
+ vakata_context.element.addClass("vakata-context-rtl").css("direction", "rtl");
654
+ }
655
+ // also apply a RTL class?
656
+ vakata_context.element.find("ul").hide().end();
657
+ });
658
+ });
659
+ }($));
660
+ // $.jstree.defaults.plugins.push("contextmenu");
661
+ }));