jstree-rails 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/INSTALLER.sh +57 -0
  4. data/LICENSE +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +2 -0
  7. data/jstree-rails.gemspec +17 -0
  8. data/lib/jstree-rails/rails.rb +6 -0
  9. data/lib/jstree-rails/version.rb +5 -0
  10. data/lib/jstree-rails.rb +8 -0
  11. data/vendor/assets/images/jstree/themes/default/d.gif +0 -0
  12. data/vendor/assets/images/jstree/themes/default/d.png +0 -0
  13. data/vendor/assets/images/jstree/themes/default/throbber.gif +0 -0
  14. data/vendor/assets/images/jstree/themes/default-rtl/d.gif +0 -0
  15. data/vendor/assets/images/jstree/themes/default-rtl/d.png +0 -0
  16. data/vendor/assets/images/jstree/themes/default-rtl/dots.gif +0 -0
  17. data/vendor/assets/images/jstree/themes/default-rtl/throbber.gif +0 -0
  18. data/vendor/assets/javascripts/jstree/index.js +15 -0
  19. data/vendor/assets/javascripts/jstree/jstree.checkbox.js +187 -0
  20. data/vendor/assets/javascripts/jstree/jstree.contextmenu.js +145 -0
  21. data/vendor/assets/javascripts/jstree/jstree.dnd.js +162 -0
  22. data/vendor/assets/javascripts/jstree/jstree.hotkeys.js +138 -0
  23. data/vendor/assets/javascripts/jstree/jstree.html.js +69 -0
  24. data/vendor/assets/javascripts/jstree/jstree.js +1982 -0
  25. data/vendor/assets/javascripts/jstree/jstree.json.js +99 -0
  26. data/vendor/assets/javascripts/jstree/jstree.rules.js +145 -0
  27. data/vendor/assets/javascripts/jstree/jstree.sort.js +38 -0
  28. data/vendor/assets/javascripts/jstree/jstree.state.js +39 -0
  29. data/vendor/assets/javascripts/jstree/jstree.themes.js +215 -0
  30. data/vendor/assets/javascripts/jstree/jstree.ui.js +201 -0
  31. data/vendor/assets/javascripts/jstree/jstree.unique.js +33 -0
  32. data/vendor/assets/javascripts/jstree/jstree.xml.js +185 -0
  33. data/vendor/assets/javascripts/jstree/vakata.js +2079 -0
  34. data/vendor/assets/stylesheets/jstree/themes/default/style.css +79 -0
  35. data/vendor/assets/stylesheets/jstree/themes/default-rtl/style.css +84 -0
  36. metadata +80 -0
@@ -0,0 +1,2079 @@
1
+ /*global XSLTProcessor: false, ActiveXObject: false, console : false */
2
+
3
+ /*
4
+ File: Helper functions
5
+ This file includes some functions that enable CSS manipulations, contextmenus, XSLT transformations and drag'n'drop.
6
+ All of those work independently of jstree.
7
+ */
8
+
9
+ /*
10
+ Variable: $.vakata
11
+ *object* Holds all helper objects.
12
+ */
13
+ (function ($) {
14
+ $.vakata = {};
15
+ })(jQuery);
16
+
17
+ /*
18
+ Group: Miscellaneous
19
+ Various small snippets.
20
+ */
21
+
22
+ /*
23
+ Function: $().vakata_reverse
24
+ Makes it possible to apply the standard array reverse function to a jQuery collection.
25
+
26
+ Input:
27
+ > <div>1</div><div>2</div><div>3</div>
28
+ > $("div").vakata_reverse().each(function () { document.write(this.innerHTML); });
29
+
30
+ Output:
31
+ >321
32
+ */
33
+ (function ($) {
34
+ $.fn.vakata_reverse = [].reverse;
35
+ })(jQuery);
36
+
37
+ (function ($) {
38
+ jQuery.expr[':'].vakata_icontains = function(a,i,m){
39
+ return (a.textContent || a.innerText || "").toLowerCase().indexOf(m[3].toLowerCase())>=0;
40
+ };
41
+ })(jQuery);
42
+
43
+ /*
44
+ Function: $.vakata.array_remove
45
+ Makes it possible to remove an item (or a group of items) form an array.
46
+ http://ejohn.org/blog/javascript-array-remove/
47
+
48
+ Input:
49
+ > $.vakata.array_remove(['a', 'b', 'c'], 1);
50
+
51
+ Output:
52
+ >['a', 'c']
53
+ */
54
+ (function ($) {
55
+ $.vakata.array_remove = function(array, from, to) {
56
+ var rest = array.slice((to || from) + 1 || array.length);
57
+ array.length = from < 0 ? array.length + from : from;
58
+ array.push.apply(array, rest);
59
+ return array;
60
+ };
61
+ })(jQuery);
62
+
63
+ /*
64
+ Function: $.vakata.array_unique
65
+ Returns only the unique items from an array.
66
+
67
+ Input:
68
+ > $.vakata.array_unique(['c','a','a','b','c','b']);
69
+
70
+ Output:
71
+ >['a', 'b', 'c']
72
+ */
73
+ (function ($) {
74
+ $.vakata.array_unique = function(array) {
75
+ var a = [], i, j, l;
76
+ for(i = 0, l = array.length; i < l; i++) {
77
+ for(j = 0; j <= i; j++) {
78
+ if(array[i] === array[j]) {
79
+ break;
80
+ }
81
+ }
82
+ if(j === i) { a.push(array[i]); }
83
+ }
84
+ return a;
85
+ };
86
+ })(jQuery);
87
+
88
+ /*
89
+ Function: $.vakata.attributes
90
+ Collects all attributes from a DOM node.
91
+ */
92
+ (function ($) {
93
+ $.vakata.attributes = function(node, with_values) {
94
+ node = $(node)[0];
95
+ var attr = with_values ? {} : [];
96
+ $.each(node.attributes, function (i, v) {
97
+ if($.inArray(v.nodeName.toLowerCase(),['style','contenteditable','hasfocus','tabindex']) !== -1) { return; }
98
+ if(v.nodeValue !== null && $.trim(v.nodeValue) !== '') {
99
+ if(with_values) { attr[v.nodeName] = v.nodeValue; }
100
+ else { attr.push(v.nodeName); }
101
+ }
102
+ });
103
+ return attr;
104
+ };
105
+ })(jQuery);
106
+
107
+ /*
108
+ Function: $.vakata.get_scrollbar_width
109
+ Gets the width of the scrollbar
110
+ */
111
+ (function ($) {
112
+ var sb;
113
+ $.vakata.get_scrollbar_width = function () {
114
+ var e1, e2;
115
+ if(!sb) {
116
+ if(/msie/.test(navigator.userAgent.toLowerCase())) {
117
+ e1 = $('<textarea cols="10" rows="2"></textarea>').css({ position: 'absolute', top: -1000, left: 0 }).appendTo('body');
118
+ e2 = $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>').css({ position: 'absolute', top: -1000, left: 0 }).appendTo('body');
119
+ sb = e1.width() - e2.width();
120
+ e1.add(e2).remove();
121
+ }
122
+ else {
123
+ e1 = $('<div />').css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: 0 })
124
+ .prependTo('body').append('<div />').find('div').css({ width: '100%', height: 200 });
125
+ sb = 100 - e1.width();
126
+ e1.parent().remove();
127
+ }
128
+ }
129
+ return sb;
130
+ };
131
+ })(jQuery);
132
+
133
+ /*
134
+ Group: CSS
135
+ Functions needed to manipulate stylesheets (add, remove, change)
136
+ */
137
+ (function ($) {
138
+ /*
139
+ Variable: $.vakata.css
140
+ *object* holds all CSS related functions
141
+ */
142
+ $.vakata.css = {
143
+ /*
144
+ Function: $.vakata.css.get_css
145
+ Retrieves or deletes a specific rule.
146
+
147
+ Parameters:
148
+ rule_name - *string* the rule to search for (any CSS rule)
149
+ delete_flag - *boolean* whether you want to delete or simply retrieve a reference to the rule
150
+ sheet - the sheet to search in (do not specify this to search in all sheets)
151
+
152
+ Returns either:
153
+ a reference to the rule - if it was found and the delete flag was not set
154
+ true - if the delete flag was set and the rule was successfully removed
155
+ false - if the rule could not be found
156
+
157
+ See also:
158
+ <$.vakata.css.remove_css>
159
+ */
160
+ get_css : function(rule_name, delete_flag, sheet) {
161
+ rule_name = rule_name.toLowerCase();
162
+ var css_rules = sheet.cssRules || sheet.rules,
163
+ j = 0;
164
+ do {
165
+ if(css_rules.length && j > css_rules.length + 5) { return false; }
166
+ if(css_rules[j].selectorText && css_rules[j].selectorText.toLowerCase() === rule_name) {
167
+ if(delete_flag === true) {
168
+ if(sheet.removeRule) { sheet.removeRule(j); }
169
+ if(sheet.deleteRule) { sheet.deleteRule(j); }
170
+ return true;
171
+ }
172
+ else { return css_rules[j]; }
173
+ }
174
+ }
175
+ while (css_rules[++j]);
176
+ return false;
177
+ },
178
+ /*
179
+ Function: $.vakata.css.add_css
180
+ Adds a rule.
181
+
182
+ Parameters:
183
+ rule_name - *string* the rule to add
184
+ sheet - a reference to the sheet to add to
185
+
186
+ Returns either:
187
+ a reference to the rule - if the rule was added
188
+ false - if the rule could not be added, or if such a rule already exists
189
+ */
190
+ add_css : function(rule_name, sheet) {
191
+ if($.jstree.css.get_css(rule_name, false, sheet)) { return false; }
192
+ if(sheet.insertRule) { sheet.insertRule(rule_name + ' { }', 0); } else { sheet.addRule(rule_name, null, 0); }
193
+ return $.vakata.css.get_css(rule_name);
194
+ },
195
+ /*
196
+ Function: $.vakata.css.remove_css
197
+ Removes a rule, this functions is a shortcut to <$.vakata.css.get_css> with the delete flag set to true.
198
+
199
+ Parameters:
200
+ rule_name - *string* the rule to remove
201
+ sheet - the sheet to remove from (you can omit this and all sheets will be searched)
202
+
203
+ Returns either:
204
+ true - if rule was removed
205
+ false - if the rule could not be removed
206
+
207
+ See also:
208
+ <$.vakata.css.get_css>
209
+ */
210
+ remove_css : function(rule_name, sheet) {
211
+ return $.vakata.css.get_css(rule_name, true, sheet);
212
+ },
213
+ /*
214
+ Function: $.vakata.css.add_sheet
215
+ Adds a whole stylesheet or appends to an existing stylesheet.
216
+
217
+ Parameters:
218
+ options - *object*:
219
+ options.url - location of the stylesheet - when this is supplied _options.str_ and _options.title_ should not be set and a new LINK element is always created
220
+ options.str - text content of the stylesheet - when this is supplied _options.url_ is not used. A STYLE element is used.
221
+ options.title - the ID of the added stylesheet (if you pass `foo` the ID will be `foo-stylesheet`), when the stylesheet exists the content is appended and no new stylesheet is created.
222
+
223
+ Returns:
224
+ a reference to the stylesheet
225
+ */
226
+ add_sheet : function(opts) {
227
+ var tmp = false, is_new = true;
228
+ if(opts.str) {
229
+ if(opts.title) { tmp = $("style[id='" + opts.title + "-stylesheet']")[0]; }
230
+ if(tmp) { is_new = false; }
231
+ else {
232
+ tmp = document.createElement("style");
233
+ tmp.setAttribute('type',"text/css");
234
+ if(opts.title) { tmp.setAttribute("id", opts.title + "-stylesheet"); }
235
+ }
236
+ if(tmp.styleSheet) {
237
+ if(is_new) {
238
+ document.getElementsByTagName("head")[0].appendChild(tmp);
239
+ tmp.styleSheet.cssText = opts.str;
240
+ }
241
+ else {
242
+ tmp.styleSheet.cssText = tmp.styleSheet.cssText + " " + opts.str;
243
+ }
244
+ }
245
+ else {
246
+ tmp.appendChild(document.createTextNode(opts.str));
247
+ document.getElementsByTagName("head")[0].appendChild(tmp);
248
+ }
249
+ return tmp.sheet || tmp.styleSheet;
250
+ }
251
+ if(opts.url) {
252
+ if(document.createStyleSheet) {
253
+ try { tmp = document.createStyleSheet(opts.url); } catch (e) { }
254
+ }
255
+ else {
256
+ tmp = document.createElement('link');
257
+ tmp.rel = 'stylesheet';
258
+ tmp.type = 'text/css';
259
+ tmp.media = "all";
260
+ tmp.href = opts.url;
261
+ document.getElementsByTagName("head")[0].appendChild(tmp);
262
+ return tmp.styleSheet;
263
+ }
264
+ }
265
+ }
266
+ };
267
+ })(jQuery);
268
+
269
+ /*
270
+ Group: Drag'n'drop
271
+ Functions needed to drag'n'drop elements
272
+ */
273
+ (function ($) {
274
+ // private variable
275
+ var vakata_dnd = {
276
+ element : false,
277
+ is_down : false,
278
+ is_drag : false,
279
+ helper : false,
280
+ helper_w: 0,
281
+ data : false,
282
+ init_x : 0,
283
+ init_y : 0,
284
+ scroll_l: 0,
285
+ scroll_t: 0,
286
+ scroll_e: false,
287
+ scroll_i: false
288
+ };
289
+ /*
290
+ Variable: $.vakata.dnd
291
+ *object* holds all DND related functions
292
+ */
293
+ $.vakata.dnd = {
294
+ /*
295
+ Variable: $.vakata.dnd.settings
296
+ *object* holds the global settings object for DND. You can easily modify any of the settings.
297
+ >// modification example
298
+ >$.vakata.dnd.settings.threshold = 10;
299
+ */
300
+ settings : {
301
+ /*
302
+ Variable: $.vakata.dnd.settings.scroll_speed
303
+ *integer* how fast (pixel count for each step) should a scrollable parent scroll when dragging near the edge. Default is _10_.
304
+ */
305
+ scroll_speed : 10,
306
+ /*
307
+ Variable: $.vakata.dnd.settings.scroll_proximity
308
+ *integer* number of pixels from the edge of a scrollable parent below which the parent will start scrolling. Default is _20_.
309
+ */
310
+ scroll_proximity : 20,
311
+ /*
312
+ Variable: $.vakata.dnd.settings.helper_left
313
+ *integer* number of pixels left of the cursor to move the drag-helper to. Default is _5_;
314
+ */
315
+ helper_left : 5,
316
+ /*
317
+ Variable: $.vakata.dnd.settings.helper_top
318
+ *integer* number of pixels below the cursor to move the drag-helper to. Default is _10_.
319
+ */
320
+ helper_top : 10,
321
+ /*
322
+ Variable: $.vakata.dnd.settings.threshold
323
+ *integer* amount of pixels required to move before the drag is started. Default is _5_.
324
+ */
325
+ threshold : 5
326
+ },
327
+ /*
328
+ Function: $.vakata.dnd._trigger
329
+ Used internally to trigger all necessary events.
330
+ */
331
+ _trigger : function (event_name, e) {
332
+ var data = $.vakata.dnd._get();
333
+ data.event = e;
334
+ $(document).triggerHandler("dnd_" + event_name + ".vakata", data);
335
+ },
336
+ /*
337
+ Function: $.vakata.dnd._get
338
+ Used internally to get all items for the drag event. Can be used by foreign code too.
339
+ */
340
+ _get : function () {
341
+ return {
342
+ "data" : vakata_dnd.data,
343
+ "element" : vakata_dnd.element,
344
+ "helper" : vakata_dnd.helper
345
+ };
346
+ },
347
+ /*
348
+ Function: $.vakata.dnd._clean
349
+ Used internally to cleanup after a drop, so that all variables are nulled and ready for the next drag.
350
+ */
351
+ _clean : function () {
352
+ if(vakata_dnd.helper) { vakata_dnd.helper.remove(); }
353
+ if(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; }
354
+ vakata_dnd = {
355
+ element : false,
356
+ is_down : false,
357
+ is_drag : false,
358
+ helper : false,
359
+ helper_w: 0,
360
+ data : false,
361
+ init_x : 0,
362
+ init_y : 0,
363
+ scroll_l: 0,
364
+ scroll_t: 0,
365
+ scroll_e: false,
366
+ scroll_i: false
367
+ };
368
+ $(document).unbind("mousemove", $.vakata.dnd.drag);
369
+ $(document).unbind("mouseup", $.vakata.dnd.stop);
370
+ },
371
+ /*
372
+ Function: $.vakata.dnd._scroll
373
+ Used internally to scroll hovered elements.
374
+
375
+ Triggers:
376
+ <dnd_scroll>
377
+
378
+ Event: dnd_scroll
379
+ Fires when a container is scrolled due to dragging near its edge. Triggered on the document, the event is fired in the *vakata* namespace.
380
+
381
+ Parameters:
382
+ data.event - the scrolled element
383
+ data.data - the data you supplied when calling <$.vakata.dnd.start>
384
+ data.element - the origin element
385
+ data.helper - the jquery extended drag-helper node (or false if it is not used)
386
+
387
+ Example:
388
+ >$(document).bind("dnd_start.vakata", function (e, data) {
389
+ > // do something
390
+ >});
391
+ */
392
+ _scroll : function (init_only) {
393
+ if(!vakata_dnd.scroll_e || (!vakata_dnd.scroll_l && !vakata_dnd.scroll_t)) {
394
+ if(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; }
395
+ return false;
396
+ }
397
+ if(!vakata_dnd.scroll_i) {
398
+ vakata_dnd.scroll_i = setInterval($.vakata.dnd._scroll, 100);
399
+ return false;
400
+ }
401
+ if(init_only === true) { return false; }
402
+
403
+ var i = vakata_dnd.scroll_e.scrollTop(),
404
+ j = vakata_dnd.scroll_e.scrollLeft();
405
+ vakata_dnd.scroll_e.scrollTop(i + vakata_dnd.scroll_t * $.vakata.dnd.settings.scroll_speed);
406
+ vakata_dnd.scroll_e.scrollLeft(j + vakata_dnd.scroll_l * $.vakata.dnd.settings.scroll_speed);
407
+ if(i !== vakata_dnd.scroll_e.scrollTop() || j !== vakata_dnd.scroll_e.scrollLeft()) {
408
+ $.vakata.dnd._trigger("scroll", vakata_dnd.scroll_e);
409
+ }
410
+ },
411
+ /*
412
+ Function: $.vakata.dnd.start
413
+ Use this function to start a drag (usually with the mousedown event)
414
+
415
+ Parameters:
416
+ event - *event* the event which started the drag, when used with the mousedown event text selection is prevented
417
+ data - *mixed* some custom data you want to bind with that particular drag - you will receive this in all events
418
+ html - *mixed* the text for the drag-helper as a *string*, if set to _false_ no helper is shown
419
+
420
+ Returns:
421
+ false
422
+
423
+ Example:
424
+ >$("span").bind("mousedown", function (e) {
425
+ > return $.vakata.dnd.start(e, {}, "Dragging");
426
+ >});
427
+ */
428
+ start : function (e, data, html) {
429
+ if(vakata_dnd.is_drag) { $.vakata.dnd.stop({}); }
430
+ try {
431
+ e.currentTarget.unselectable = "on";
432
+ e.currentTarget.onselectstart = function() { return false; };
433
+ if(e.currentTarget.style) { e.currentTarget.style.MozUserSelect = "none"; }
434
+ } catch(err) { }
435
+ vakata_dnd.init_x = e.pageX;
436
+ vakata_dnd.init_y = e.pageY;
437
+ vakata_dnd.data = data;
438
+ vakata_dnd.is_down = true;
439
+ vakata_dnd.element = e.currentTarget;
440
+ if(html !== false) {
441
+ vakata_dnd.helper = $("<div id='vakata-dnd'></div>").html(html).css({
442
+ "display" : "block",
443
+ "margin" : "0",
444
+ "padding" : "0",
445
+ "position" : "absolute",
446
+ "top" : "-2000px",
447
+ "lineHeight" : "16px",
448
+ "zIndex" : "10000"
449
+ });
450
+ }
451
+ $(document).bind("mousemove", $.vakata.dnd.drag);
452
+ $(document).bind("mouseup", $.vakata.dnd.stop);
453
+ return false;
454
+ },
455
+ /*
456
+ Function: $.vakata.dnd.drag
457
+ Used internally to process the mousemove event after <$.vakata.dnd.start> is called.
458
+
459
+ Parameters:
460
+ event - *event* the mousemove event
461
+
462
+ Triggers:
463
+ <dnd_start>, <dnd_move>
464
+ */
465
+ drag : function (e) {
466
+ if(!vakata_dnd.is_down) { return; }
467
+ if(!vakata_dnd.is_drag) {
468
+ if(
469
+ Math.abs(e.pageX - vakata_dnd.init_x) > $.vakata.dnd.settings.threshold ||
470
+ Math.abs(e.pageY - vakata_dnd.init_y) > $.vakata.dnd.settings.threshold
471
+ ) {
472
+ if(vakata_dnd.helper) {
473
+ vakata_dnd.helper.appendTo("body");
474
+ vakata_dnd.helper_w = vakata_dnd.helper.outerWidth();
475
+ }
476
+ vakata_dnd.is_drag = true;
477
+ /*
478
+ Event: dnd_start
479
+ Marks the start of the drag. Triggered on the document after a drag is initiated using <$.vakata.dnd.start> and the user has moved more than <$.vakata.dnd.settings.threshold> pixels, the event is fired in the *vakata* namespace.
480
+
481
+ Parameters:
482
+ data.event - the mousemove event
483
+ data.data - the data you supplied when calling <$.vakata.dnd.start>
484
+ data.element - the origin element
485
+ data.helper - the jquery extended drag-helper node (or false if it is not used)
486
+
487
+ Example:
488
+ >$(document).bind("dnd_start.vakata", function (e, data) {
489
+ > // do something
490
+ >});
491
+ */
492
+ $.vakata.dnd._trigger("start", e);
493
+ }
494
+ else { return; }
495
+ }
496
+
497
+ var d = false, w = false,
498
+ dh = false, wh = false,
499
+ dw = false, ww = false,
500
+ dt = false, dl = false,
501
+ ht = false, hl = false;
502
+
503
+ vakata_dnd.scroll_t = 0;
504
+ vakata_dnd.scroll_l = 0;
505
+ vakata_dnd.scroll_e = false;
506
+ var p = $(e.target)
507
+ .parentsUntil("body").andSelf().vakata_reverse()
508
+ .filter(function () {
509
+ return (/^auto|scroll$/).test($(this).css("overflow")) &&
510
+ (this.scrollHeight > this.offsetHeight || this.scrollWidth > this.offsetWidth);
511
+ })
512
+ .each(function () {
513
+ var t = $(this), o = t.offset();
514
+ if(this.scrollHeight > this.offsetHeight) {
515
+ if(o.top + t.height() - e.pageY < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_t = 1; }
516
+ if(e.pageY - o.top < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_t = -1; }
517
+ }
518
+ if(this.scrollWidth > this.offsetWidth) {
519
+ if(o.left + t.width() - e.pageX < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_l = 1; }
520
+ if(e.pageX - o.left < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_l = -1; }
521
+ }
522
+ if(vakata_dnd.scroll_t || vakata_dnd.scroll_l) {
523
+ vakata_dnd.scroll_e = $(this);
524
+ return false;
525
+ }
526
+ });
527
+
528
+ if(!vakata_dnd.scroll_e) {
529
+ d = $(document); w = $(window);
530
+ dh = d.height(); wh = w.height();
531
+ dw = d.width(); ww = w.width();
532
+ dt = d.scrollTop(); dl = d.scrollLeft();
533
+ if(dh > wh && e.pageY - dt < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_t = -1; }
534
+ if(dh > wh && wh - (e.pageY - dt) < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_t = 1; }
535
+ if(dw > ww && e.pageX - dl < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_l = -1; }
536
+ if(dw > ww && ww - (e.pageX - dl) < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_l = 1; }
537
+ if(vakata_dnd.scroll_t || vakata_dnd.scroll_l) {
538
+ vakata_dnd.scroll_e = d;
539
+ }
540
+ }
541
+ if(vakata_dnd.scroll_e) { $.vakata.dnd._scroll(true); }
542
+
543
+ if(vakata_dnd.helper) {
544
+ ht = parseInt(e.pageY + $.vakata.dnd.settings.helper_top, 10);
545
+ hl = parseInt(e.pageX + $.vakata.dnd.settings.helper_left, 10);
546
+ if(dh && ht + 25 > dh) { ht = dh - 50; }
547
+ if(dw && hl + vakata_dnd.helper_w > dw) { hl = dw - (vakata_dnd.helper_w + 2); }
548
+ vakata_dnd.helper.css({
549
+ left : hl + "px",
550
+ top : ht + "px"
551
+ });
552
+ }
553
+ /*
554
+ Event: dnd_move
555
+ Triggered multiple times while dragging. This event is triggered on the document after the <dnd_start> event when the user moves the mouse, the event is fired in the *vakata* namespace.
556
+
557
+ Parameters:
558
+ data.event - the mousemove event
559
+ data.data - the data you supplied when calling <$.vakata.dnd.start>
560
+ data.element - the origin element
561
+ data.helper - the jquery extended drag-helper node (or false if it is not used)
562
+
563
+ Example:
564
+ >$(document).bind("dnd_move.vakata", function (e, data) {
565
+ > // do something
566
+ >});
567
+ */
568
+ $.vakata.dnd._trigger("move", e);
569
+ },
570
+ /*
571
+ Function: $.vakata.dnd.stop
572
+ Used internally to process the mouseup event (drop) after <$.vakata.dnd.start> is called.
573
+
574
+ Parameters:
575
+ event - *event* the mouseup event
576
+
577
+ Triggers:
578
+ <dnd_stop>
579
+ */
580
+ stop : function (e) {
581
+ /*
582
+ Event: dnd_stop
583
+ Marks the end of the drag. This event is triggered on the document after <dnd_start> (and possibly <dnd_move>) when a drop (mouseup) occurs or when the drag is programatically terminated, the event is fired in the *vakata* namespace.
584
+
585
+ Parameters:
586
+ data.event - the mouseup event (or _null_ if stopped programatically using <$.vakata.dnd.stop>())
587
+ data.data - the data you supplied when calling <$.vakata.dnd.start>
588
+ data.element - the origin element
589
+ data.helper - the jquery extended drag-helper node (or false if it is not used)
590
+
591
+ Example:
592
+ >$(document).bind("dnd_stop.vakata", function (e, data) {
593
+ > // do something
594
+ >});
595
+ */
596
+ if(vakata_dnd.is_drag) {
597
+ $.vakata.dnd._trigger("stop", e);
598
+ }
599
+ $.vakata.dnd._clean();
600
+ }
601
+ };
602
+ })(jQuery);
603
+
604
+ /*
605
+ Group: XSLT
606
+ A function used to do XSLT transformations.
607
+ */
608
+ (function ($) {
609
+ /*
610
+ Function: $.vakata.xslt
611
+ This functions transforms a XML string using a XSL string. The result is passed to a callback function.
612
+
613
+ Parameters:
614
+ xml - *string* the source xml string
615
+ xsl - *string* the xsl string
616
+
617
+ Returns:
618
+ the transformed result (or _false_ on failure)
619
+
620
+ Example:
621
+ >// simple
622
+ >$.vakata.xslt("<xml-string-here>", "<xsl-string-here>", function (res) { $("#some-container").append(res); });
623
+ >// with scope
624
+ >$.vakata.xslt("<xml-string-here>", "<xsl-string-here>", $.proxy(function (res) {
625
+ > this.some_process(res);
626
+ >}, some_object);
627
+ */
628
+ $.vakata.xslt = function (xml, xsl) {
629
+ var r = false, p, q, s;
630
+ // IE9
631
+ if(r === false && window.ActiveXObject) {
632
+ try {
633
+ r = new ActiveXObject("Msxml2.XSLTemplate");
634
+ q = new ActiveXObject("Msxml2.DOMDocument");
635
+ q.loadXML(xml);
636
+ s = new ActiveXObject("Msxml2.FreeThreadedDOMDocument");
637
+ s.loadXML(xsl);
638
+ r.stylesheet = s;
639
+ p = r.createProcessor();
640
+ p.input = q;
641
+ p.transform();
642
+ r = p.output;
643
+ }
644
+ catch (e) { }
645
+ }
646
+ xml = $.parseXML(xml);
647
+ xsl = $.parseXML(xsl);
648
+ // FF, Chrome
649
+ if(r === false && typeof (XSLTProcessor) !== "undefined") {
650
+ p = new XSLTProcessor();
651
+ p.importStylesheet(xsl);
652
+ r = p.transformToFragment(xml, document);
653
+ r = $('<div />').append(r).html();
654
+ }
655
+ // OLD IE
656
+ if(r === false && typeof (xml.transformNode) !== "undefined") {
657
+ r = xml.transformNode(xsl);
658
+ }
659
+ return r;
660
+ };
661
+ })(jQuery);
662
+
663
+ /*
664
+ Group: Hotkeys
665
+ Copy of the John Resig's fork of http://github.com/tzuryby/hotkeys for consistency
666
+ */
667
+ if(typeof jQuery.hotkeys === "undefined") {
668
+ (function ($) {
669
+ $.vakata_hotkeys = {
670
+ version: "0.8",
671
+
672
+ specialKeys: {
673
+ 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
674
+ 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
675
+ 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
676
+ 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
677
+ 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
678
+ 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
679
+ 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
680
+ },
681
+
682
+ shiftNums: {
683
+ "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
684
+ "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
685
+ ".": ">", "/": "?", "\\": "|"
686
+ }
687
+ };
688
+
689
+ function keyHandler( handleObj ) {
690
+ // Only care when a possible input has been specified
691
+ if ( typeof handleObj.data !== "string" ) {
692
+ return;
693
+ }
694
+
695
+ var origHandler = handleObj.handler,
696
+ keys = handleObj.data.toLowerCase().split(" ");
697
+
698
+ handleObj.handler = function( event ) {
699
+ // Don't fire in text-accepting inputs that we didn't directly bind to
700
+ if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
701
+ event.target.type === "text") ) {
702
+ return;
703
+ }
704
+
705
+ // Keypress represents characters, not special keys
706
+ var special = event.type !== "keypress" && jQuery.vakata_hotkeys.specialKeys[ event.which ],
707
+ character = String.fromCharCode( event.which ).toLowerCase(),
708
+ key, modif = "", possible = {};
709
+
710
+ // check combinations (alt|ctrl|shift+anything)
711
+ if ( event.altKey && special !== "alt" ) {
712
+ modif += "alt+";
713
+ }
714
+
715
+ if ( event.ctrlKey && special !== "ctrl" ) {
716
+ modif += "ctrl+";
717
+ }
718
+
719
+ // TODO: Need to make sure this works consistently across platforms
720
+ if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
721
+ modif += "meta+";
722
+ }
723
+
724
+ if ( event.shiftKey && special !== "shift" ) {
725
+ modif += "shift+";
726
+ }
727
+
728
+ if ( special ) {
729
+ possible[ modif + special ] = true;
730
+
731
+ } else {
732
+ possible[ modif + character ] = true;
733
+ possible[ modif + jQuery.vakata_hotkeys.shiftNums[ character ] ] = true;
734
+
735
+ // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
736
+ if ( modif === "shift+" ) {
737
+ possible[ jQuery.vakata_hotkeys.shiftNums[ character ] ] = true;
738
+ }
739
+ }
740
+
741
+ for ( var i = 0, l = keys.length; i < l; i++ ) {
742
+ if ( possible[ keys[i] ] ) {
743
+ return origHandler.apply( this, arguments );
744
+ }
745
+ }
746
+ };
747
+ }
748
+
749
+ jQuery.each([ "keydown", "keyup", "keypress" ], function() {
750
+ jQuery.event.special[ this ] = { add: keyHandler };
751
+ });
752
+ })(jQuery);
753
+ }
754
+
755
+ /*
756
+ Group: Context menu
757
+ Functions needed to show a custom context menu.
758
+ */
759
+ (function ($) {
760
+ var right_to_left = false,
761
+ vakata_context = {
762
+ element : false,
763
+ reference : false,
764
+ position_x : 0,
765
+ position_y : 0,
766
+ items : [],
767
+ html : "",
768
+ is_visible : false
769
+ };
770
+ /*
771
+ Variable: $.vakata.context
772
+ *object* holds all context menu related functions and variables.
773
+ */
774
+ $.vakata.context = {
775
+ /*
776
+ Variable: $.vakata.context.settings
777
+ *object* holds the global settings object for context menus. You can easily modify any of the settings.
778
+ >// modification example
779
+ >$.vakata.context.settings.icons = false;
780
+ */
781
+ settings : {
782
+ /*
783
+ Variable: $.vakata.context.settings.hide_onmouseleave
784
+ *integer* the amount of milliseconds to wait before hiding the menu after mouseleave. If set to _0_ the menu won't hide on mouseleave. Default is _0_.
785
+ */
786
+ hide_onmouseleave : 0,
787
+ /*
788
+ Variable: $.vakata.context.settings.icons
789
+ *boolean* whether to show icons or not. Default is _true_.
790
+ */
791
+ icons : true
792
+ },
793
+ /*
794
+ Function: $.vakata.context._trigger
795
+ Used internally to trigger all necessary events.
796
+ */
797
+ _trigger : function (event_name) {
798
+ $(document).triggerHandler("context_" + event_name + ".vakata", {
799
+ "reference" : vakata_context.reference,
800
+ "element" : vakata_context.element,
801
+ "position" : {
802
+ "x" : vakata_context.position_x,
803
+ "y" : vakata_context.position_y
804
+ }
805
+ });
806
+ },
807
+ /*
808
+ Function: $.vakata.context._execute
809
+ Used internally to execute the action (if any) associated with an item.
810
+
811
+ Parameters:
812
+ i - the item's internal index
813
+ */
814
+ _execute : function (i) {
815
+ i = vakata_context.items[i];
816
+ return i && !i._disabled && i.action ? i.action.call(null, {
817
+ "item" : i,
818
+ "reference" : vakata_context.reference,
819
+ "element" : vakata_context.element,
820
+ "position" : {
821
+ "x" : vakata_context.position_x,
822
+ "y" : vakata_context.position_y
823
+ }
824
+ }) : false;
825
+ },
826
+ /*
827
+ Function: $.vakata.context._parse
828
+ Used internally to parse a contextmenu description object to an HTML string.
829
+
830
+ Parameters:
831
+ o - *object* the contextmenu description object
832
+ is_callback - *boolean* used internally to indicate a recursive call
833
+
834
+ Triggers:
835
+ <context_parse>
836
+ */
837
+ _parse : function (o, is_callback) {
838
+ if(!o) { return false; }
839
+ if(!is_callback) {
840
+ vakata_context.html = "";
841
+ vakata_context.items = [];
842
+ }
843
+ var str = "",
844
+ sep = false,
845
+ tmp;
846
+
847
+ if(is_callback) { str += "<ul>"; }
848
+ $.each(o, function (i, val) {
849
+ if(!val) { return true; }
850
+ vakata_context.items.push(val);
851
+ if(!sep && val.separator_before) {
852
+ str += "<li class='vakata-context-separator'><a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + ">&#160;</a></li>";
853
+ }
854
+ sep = false;
855
+ str += "<li class='" + (val._class || "") + (val._disabled ? " vakata-contextmenu-disabled " : "") + "'>";
856
+ str += "<a href='#' rel='" + (vakata_context.items.length - 1) + "'>";
857
+ if($.vakata.context.settings.icons) {
858
+ str += "<ins ";
859
+ if(val.icon) {
860
+ if(val.icon.indexOf("/") !== -1) { str += " style='background:url(\"" + val.icon + "\") center center no-repeat' "; }
861
+ else { str += " class='" + val.icon + "' "; }
862
+ }
863
+ str += ">&#160;</ins><span>&#160;</span>";
864
+ }
865
+ str += val.label + "</a>";
866
+ if(val.submenu) {
867
+ tmp = $.vakata.context._parse(val.submenu, true);
868
+ if(tmp) { str += tmp; }
869
+ }
870
+ str += "</li>";
871
+ if(val.separator_after) {
872
+ str += "<li class='vakata-context-separator'><a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + ">&#160;</a></li>";
873
+ sep = true;
874
+ }
875
+ });
876
+ str = str.replace(/<li class\='vakata-context-separator'\><\/li\>$/,"");
877
+ if(is_callback) { str += "</ul>"; }
878
+ /*
879
+ Event: context_parse
880
+ Triggered when the context menu is parsed but not yet shown. This event is triggered on the document in the *vakata* namespace.
881
+
882
+ Parameters:
883
+ reference - the DOM node used when <$.vakata.context.show> was called
884
+ element - the DOM node of the context menu (not yet populated and shown)
885
+ position - an object consisting of _x_ and _y_ keys, represinting the position of the menu (not yet shown)
886
+
887
+ Example:
888
+ >$(document).bind("context_parse.vakata", function (e, data) {
889
+ > // do something
890
+ >});
891
+ */
892
+ if(!is_callback) { vakata_context.html = str; $.vakata.context._trigger("parse"); }
893
+ return str.length > 10 ? str : false;
894
+ },
895
+ /*
896
+ Function: $.vakata.context._show_submenu
897
+ Used internally to show a submenu
898
+ */
899
+ _show_submenu : function (o) {
900
+ o = $(o);
901
+ if(!o.length || !o.children("ul").length) { return; }
902
+ var e = o.children("ul"),
903
+ x = o.offset().left + o.outerWidth(),
904
+ y = o.offset().top,
905
+ w = e.width(),
906
+ h = e.height(),
907
+ dw = $(document).width(),
908
+ dh = $(document).height();
909
+ // може да се спести е една проверка - дали няма някой от класовете вече нагоре
910
+ if(right_to_left) {
911
+ o[x - (w + 10 + o.outerWidth()) < 0 ? "addClass" : "removeClass"]("vakata-context-left");
912
+ }
913
+ else {
914
+ o[x + w + 10 > dw ? "addClass" : "removeClass"]("vakata-context-right");
915
+ }
916
+ if(y + h + 10 > dh) {
917
+ e.css("bottom","-1px");
918
+ }
919
+ e.show();
920
+ },
921
+
922
+ /*
923
+ Function: $.vakata.context.show
924
+ Shows the context menu. Please note that at least one of _reference_ or _position_ should be specified.
925
+
926
+ Parameters:
927
+ reference - *jquery* associate the menu with a DOM element (optional)
928
+ position - *object* should contain _x_ and _y_ properties, those are the coordinates to show the menu at (optional
929
+ data - *object* the contextmenu description object. It should consist of keys, each key should be a <context_menu_item>. If not specified the function will search for $(reference).data('vakata_contextmenu') and use that.
930
+
931
+ Triggers:
932
+ <context_show>
933
+
934
+ Example:
935
+ >$(document).bind("contextmenu", function (e) {
936
+ > e.preventDefault();
937
+ > $.vakata.context.show(false, { x: e.pageX, y:e.pageY }, {
938
+ > "create" : {
939
+ > // only specify what you need
940
+ > "separator_after" : true,
941
+ > "label" : "Create",
942
+ > "action" : function (data) { alert("Create"); }
943
+ > },
944
+ > "rename" : {
945
+ > "label" : "Rename",
946
+ > "icon" : "./some-icon.png",
947
+ > "action" : function (data) { alert("Rename on " + data.reference); }
948
+ > },
949
+ > "edit" : {
950
+ > "label" : "Edit",
951
+ > // Clicking this won't hide the menu, the same can be achieved with:
952
+ > // "action" : function () { return false; }
953
+ > "submenu" : {
954
+ > "copy" : { "label" : "Copy", "action" : function () { } },
955
+ > "cut" : { "label" : "Cut", "action" : function () { } },
956
+ > "paste" : { "label" : "Paste", "_disabled" : true, "action" : function () { } }
957
+ > }
958
+ > },
959
+ > "delete" : {
960
+ > "separator_before" : true,
961
+ > "label" : "Delete",
962
+ > "action" : function (data) { alert("Delete"); }
963
+ > }
964
+ > });
965
+ >});
966
+
967
+ Variable: context_menu_item
968
+ *object* Used to construct a context menu entry, this structure will always be a part of an object.
969
+
970
+ separator_before - *boolean* should there be a separator before the item. Default is _false_.
971
+ separator_after - *boolean* should there be a separator after the item. Default is _false_.
972
+ icon - *string* if supplied this string is used for an icon, if it contains _/_ it is treated as file, otherwise it is applied as a class on an INS object.
973
+ label - *string* the text for this item
974
+ submenu - *object* if supplied this object is used to build a submenu. It should consist of keys, each of which is a <context_menu_item>.
975
+ _class - *string* if supplied this class is applied to the LI node.
976
+ _disabled - *boolean* is this item disabled.
977
+ action - *functon* if supplied it will be executed when this item is clicked / activated. If not supplied or the function returns _false_ the contextmenu won't be hidden after execution. To force a context use _$.proxy_.
978
+ In the function you will receive a single argument which is an object, consisting of four keys:
979
+ _item_ (the <context_menu_item> object),
980
+ _reference_ (the DOM node used when <$.vakata.context.show> was called),
981
+ _element_ (the DOM node of the context menu),
982
+ _position_ (an object consisting of _x_ and _y_ keys, represinting the current position of the menu)
983
+
984
+ See also:
985
+ <$.vakata.context.show>
986
+ */
987
+ show : function (reference, position, data) {
988
+ if(vakata_context.element && vakata_context.element.length) {
989
+ vakata_context.element.width('');
990
+ }
991
+ switch(!0) {
992
+ case (!position && !reference):
993
+ return false;
994
+ case (!!position && !!reference):
995
+ vakata_context.reference = reference;
996
+ vakata_context.position_x = position.x;
997
+ vakata_context.position_y = position.y;
998
+ break;
999
+ case (!position && !!reference):
1000
+ vakata_context.reference = reference;
1001
+ var o = reference.offset();
1002
+ vakata_context.position_x = o.left + reference.outerHeight();
1003
+ vakata_context.position_y = o.top;
1004
+ break;
1005
+ case (!!position && !reference):
1006
+ vakata_context.position_x = position.x;
1007
+ vakata_context.position_y = position.y;
1008
+ break;
1009
+ }
1010
+ if(!!reference && !data && $(reference).data('vakata_contextmenu')) {
1011
+ data = $(reference).data('vakata_contextmenu');
1012
+ }
1013
+ if($.vakata.context._parse(data)) {
1014
+ vakata_context.element.html(vakata_context.html);
1015
+ }
1016
+ if(vakata_context.items.length) {
1017
+ var e = vakata_context.element,
1018
+ x = vakata_context.position_x,
1019
+ y = vakata_context.position_y,
1020
+ w = e.width(),
1021
+ h = e.height(),
1022
+ dw = $(document).width(),
1023
+ dh = $(document).height();
1024
+
1025
+ if(x + w + 20 > dw) {
1026
+ x = dw - (w + 20);
1027
+ }
1028
+ if(y + h + 20 > dh) {
1029
+ y = dh - (h + 20);
1030
+ }
1031
+
1032
+ vakata_context.element
1033
+ .css({ "left" : x, "top" : y })
1034
+ .show()
1035
+ .width(vakata_context.element.outerWidth()); // for ie6
1036
+ vakata_context.is_visible = true;
1037
+ /*
1038
+ Event: context_show
1039
+ Triggered when the context menu is shown. This event is triggered on the document in the *vakata* namespace.
1040
+
1041
+ Parameters:
1042
+ reference - the DOM node used when <$.vakata.context.show> was called
1043
+ element - the DOM node of the context menu
1044
+ position - an object consisting of _x_ and _y_ keys, represinting the position of the menu
1045
+
1046
+ Example:
1047
+ >$(document).bind("context_show.vakata", function (e, data) {
1048
+ > // do something
1049
+ >});
1050
+ */
1051
+ $.vakata.context._trigger("show");
1052
+ }
1053
+ },
1054
+ /*
1055
+ Function: $.vakata.context.hide
1056
+ Used internally to hide the contextmenu after a click, or on mouseleave, etc.
1057
+
1058
+ Triggers:
1059
+ <context_hide>
1060
+ */
1061
+ hide : function () {
1062
+ if(vakata_context.is_visible) {
1063
+ vakata_context.element.hide().find("ul").hide();
1064
+ vakata_context.is_visible = false;
1065
+ /*
1066
+ Event: context_hide
1067
+ Triggered when the context menu is hidden. This event is triggered on the document in the *vakata* namespace.
1068
+
1069
+ Parameters:
1070
+ reference - the DOM node used when <$.vakata.context.show> was called
1071
+ element - the DOM node of the context menu
1072
+ position - an object consisting of _x_ and _y_ keys, represinting the position of the menu
1073
+
1074
+ Example:
1075
+ >$(document).bind("context_hide.vakata", function (e, data) {
1076
+ > // do something
1077
+ >});
1078
+ */
1079
+ $.vakata.context._trigger("hide");
1080
+ }
1081
+ }
1082
+ };
1083
+ $(function () {
1084
+ right_to_left = $("body").css("direction") === "rtl";
1085
+ var to = false,
1086
+ css_string = '' +
1087
+ '.vakata-context { display:none; _width:1px; } ' +
1088
+ '.vakata-context, ' +
1089
+ '.vakata-context ul { margin:0; padding:2px; position:absolute; background:#f5f5f5; border:1px solid #979797; ' +
1090
+ ' -moz-box-shadow:5px 5px 4px -4px #666666; -webkit-box-shadow:2px 2px 2px #999999; box-shadow:2px 2px 2px #999999; }' +
1091
+ '.vakata-context ul { list-style:none; left:100%; margin-top:-2.7em; margin-left:-4px; } ' +
1092
+ '.vakata-context li.vakata-context-right ul { left:auto; right:100%; margin-left:auto; margin-right:-4px; } ' +
1093
+ '.vakata-context li { list-style:none; display:inline; }' +
1094
+ '.vakata-context li a { display:block; padding:0 2em 0 2em; text-decoration:none; width:auto; color:black; white-space:nowrap; line-height:2.4em; ' +
1095
+ ' -moz-text-shadow:1px 1px 0px white; -webkit-text-shadow:1px 1px 0px white; text-shadow:1px 1px 0px white; ' +
1096
+ ' -moz-border-radius:1px; -webkit-border-radius:1px; border-radius:1px; }' +
1097
+ '.vakata-context li a:hover { position:relative; background-color:#e8eff7; ' +
1098
+ ' -moz-box-shadow:0px 0px 2px #0a6aa1; -webkit-box-shadow:0px 0px 2px #0a6aa1; box-shadow:0px 0px 2px #0a6aa1; }' +
1099
+ '.vakata-context li.vakata-context-hover > a { position:relative; background-color:#e8eff7; ' +
1100
+ ' -moz-box-shadow:0px 0px 2px #0a6aa1; -webkit-box-shadow:0px 0px 2px #0a6aa1; box-shadow:0px 0px 2px #0a6aa1; }' +
1101
+ '.vakata-context li a.vakata-context-parent { background-image:url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAIORI4JlrqN1oMSnmmZDQUAOw=="); background-position:right center; background-repeat:no-repeat; } ' +
1102
+ '.vakata-context li.vakata-context-separator a, ' +
1103
+ '.vakata-context li.vakata-context-separator a:hover { background:white; border:0; border-top:1px solid #e2e3e3; height:1px; min-height:1px; max-height:1px; padding:0; margin:0 0 0 2.4em; border-left:1px solid #e0e0e0; _overflow:hidden; ' +
1104
+ ' -moz-text-shadow:0 0 0 transparent; -webkit-text-shadow:0 0 0 transparent; text-shadow:0 0 0 transparent; ' +
1105
+ ' -moz-box-shadow:0 0 0 transparent; -webkit-box-shadow:0 0 0 transparent; box-shadow:0 0 0 transparent; ' +
1106
+ ' -moz-border-radius:0; -webkit-border-radius:0; border-radius:0; }' +
1107
+ '.vakata-context li.vakata-contextmenu-disabled a, .vakata-context li.vakata-contextmenu-disabled a:hover { color:silver; background-color:transparent; border:0; box-shadow:0 0 0; }' +
1108
+ '' +
1109
+ '.vakata-context li a ins { text-decoration:none; display:inline-block; width:2.4em; height:2.4em; background:transparent; margin:0 0 0 -2em; } ' +
1110
+ '.vakata-context li a span { display:inline-block; width:1px; height:2.4em; background:white; margin:0 0.5em 0 0; border-left:1px solid #e2e3e3; _overflow:hidden; } ' +
1111
+ '' +
1112
+ '.vakata-context-rtl ul { left:auto; right:100%; margin-left:auto; margin-right:-4px; } ' +
1113
+ '.vakata-context-rtl li a.vakata-context-parent { background-image:url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAINjI+AC7rWHIsPtmoxLAA7"); background-position:left center; background-repeat:no-repeat; } ' +
1114
+ '.vakata-context-rtl li.vakata-context-separator a { margin:0 2.4em 0 0; border-left:0; border-right:1px solid #e2e3e3;} ' +
1115
+ '.vakata-context-rtl li.vakata-context-left ul { right:auto; left:100%; margin-left:-4px; margin-right:auto; } ' +
1116
+ '.vakata-context-rtl li a ins { margin:0 -2em 0 0; } ' +
1117
+ '.vakata-context-rtl li a span { margin:0 0 0 0.5em; border-left-color:white; background:#e2e3e3; } ' +
1118
+ '';
1119
+ $.vakata.css.add_sheet({ str : css_string, title : "vakata-context" });
1120
+
1121
+ vakata_context.element = $("<ul class='vakata-context'></ul>");
1122
+ vakata_context.element
1123
+ .delegate("li", "mouseenter", function (e) {
1124
+ e.stopImmediatePropagation();
1125
+
1126
+ if($.contains(this, e.relatedTarget)) {
1127
+ // премахнато заради delegate mouseleave по-долу
1128
+ // $(this).find(".vakata-context-hover").removeClass("vakata-context-hover");
1129
+ return;
1130
+ }
1131
+
1132
+ if(to) { clearTimeout(to); }
1133
+ vakata_context.element.find(".vakata-context-hover").removeClass("vakata-context-hover").end();
1134
+
1135
+ $(this)
1136
+ .siblings().find("ul").hide().end().end()
1137
+ .parentsUntil(".vakata-context", "li").andSelf().addClass("vakata-context-hover");
1138
+ $.vakata.context._show_submenu(this);
1139
+ })
1140
+ // тестово - дали не натоварва?
1141
+ .delegate("li", "mouseleave", function (e) {
1142
+ if($.contains(this, e.relatedTarget)) { return; }
1143
+ $(this).find(".vakata-context-hover").andSelf().removeClass("vakata-context-hover");
1144
+ })
1145
+ .bind("mouseleave", function (e) {
1146
+ $(this).find(".vakata-context-hover").removeClass("vakata-context-hover");
1147
+ if($.vakata.context.settings.hide_onmouseleave) {
1148
+ to = setTimeout(
1149
+ (function (t) {
1150
+ return function () { $.vakata.context.hide(); };
1151
+ })(this), $.vakata.context.settings.hide_onmouseleave);
1152
+ }
1153
+ })
1154
+ .delegate("a", "click", function (e) {
1155
+ e.preventDefault();
1156
+ })
1157
+ .delegate("a", "mouseup", function (e) {
1158
+ if(!$(this).blur().parent().hasClass("vakata-context-disabled") && $.vakata.context._execute($(this).attr("rel")) !== false) {
1159
+ $.vakata.context.hide();
1160
+ }
1161
+ })
1162
+ .appendTo("body");
1163
+
1164
+ $(document)
1165
+ .bind("mousedown", function (e) {
1166
+ if(vakata_context.is_visible && !$.contains(vakata_context.element[0], e.target)) { $.vakata.context.hide(); }
1167
+ })
1168
+ .bind("context_show.vakata", function (e, data) {
1169
+ vakata_context.element.find("li:has(ul)").children("a").addClass("vakata-context-parent");
1170
+ if(right_to_left) {
1171
+ vakata_context.element.addClass("vakata-context-rtl").css("direction", "rtl");
1172
+ }
1173
+ // also apply a RTL class?
1174
+ vakata_context.element.find("ul").hide().end();
1175
+ });
1176
+
1177
+ if(typeof $.hotkeys !== "undefined" || typeof $.vakata_hotkeys !== "undefined") {
1178
+ $(document)
1179
+ .bind("keydown", "up", function (e) {
1180
+ if(vakata_context.is_visible) {
1181
+ var o = vakata_context.element.find("ul:visible").andSelf().last().children(".vakata-context-hover").removeClass("vakata-context-hover").prevAll("li:not(.vakata-context-separator)").first();
1182
+ if(!o.length) { o = vakata_context.element.find("ul:visible").andSelf().last().children("li:not(.vakata-context-separator)").last(); }
1183
+ o.addClass("vakata-context-hover");
1184
+ e.stopImmediatePropagation();
1185
+ e.preventDefault();
1186
+ }
1187
+ })
1188
+ .bind("keydown", "down", function (e) {
1189
+ if(vakata_context.is_visible) {
1190
+ var o = vakata_context.element.find("ul:visible").andSelf().last().children(".vakata-context-hover").removeClass("vakata-context-hover").nextAll("li:not(.vakata-context-separator)").first();
1191
+ if(!o.length) { o = vakata_context.element.find("ul:visible").andSelf().last().children("li:not(.vakata-context-separator)").first(); }
1192
+ o.addClass("vakata-context-hover");
1193
+ e.stopImmediatePropagation();
1194
+ e.preventDefault();
1195
+ }
1196
+ })
1197
+ .bind("keydown", "right", function (e) {
1198
+ if(vakata_context.is_visible) {
1199
+ 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");
1200
+ e.stopImmediatePropagation();
1201
+ e.preventDefault();
1202
+ }
1203
+ })
1204
+ .bind("keydown", "left", function (e) {
1205
+ if(vakata_context.is_visible) {
1206
+ vakata_context.element.find(".vakata-context-hover").last().parents("li:eq(0)").find("ul").hide().find(".vakata-context-hover").removeClass("vakata-context-hover");
1207
+ e.stopImmediatePropagation();
1208
+ e.preventDefault();
1209
+ }
1210
+ })
1211
+ .bind("keydown", "esc", function (e) {
1212
+ $.vakata.context.hide();
1213
+ e.preventDefault();
1214
+ })
1215
+ .bind("keydown", "space", function (e) {
1216
+ vakata_context.element.find(".vakata-context-hover").last().children("a").click();
1217
+ e.preventDefault();
1218
+ });
1219
+ }
1220
+ });
1221
+ })(jQuery);
1222
+
1223
+ /*
1224
+ Group: JSON
1225
+ Functions needed to encode/decode JSON. Based on the jQuery JSON Plugin.
1226
+ */
1227
+ (function ($) {
1228
+ // private function for quoting strings
1229
+ var _quote = function (str) {
1230
+ var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g,
1231
+ meta = { '\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"' :'\\"','\\':'\\\\' };
1232
+ if(str.match(escapeable)) {
1233
+ return '"' + str.replace(escapeable, function (a) {
1234
+ var c = meta[a];
1235
+ if(typeof c === 'string') { return c; }
1236
+ c = a.charCodeAt();
1237
+ return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
1238
+ }) + '"';
1239
+ }
1240
+ return '"' + str + '"';
1241
+ };
1242
+ /*
1243
+ Variable: $.vakata.json
1244
+ *object* holds all JSON related functions.
1245
+ */
1246
+ $.vakata.json = {
1247
+ /*
1248
+ Function: $.vakata.json.encode
1249
+ A function for encoding data in a JSON notated string.
1250
+
1251
+ Parameters:
1252
+ o - *mixed* the data to be encoded
1253
+
1254
+ Returns:
1255
+ string - the encoded data
1256
+ */
1257
+ encode : function (o) {
1258
+ if (o === null) { return "null"; }
1259
+
1260
+ var tmp = [], i;
1261
+ switch(typeof(o)) {
1262
+ case "undefined":
1263
+ return undefined;
1264
+ case "number":
1265
+ case "boolean":
1266
+ return o + "";
1267
+ case "string":
1268
+ return _quote(o);
1269
+ case "object":
1270
+ if($.isFunction(o.toJSON)) {
1271
+ return $.vakata.json.encode(o.toJSON());
1272
+ }
1273
+ if(o.constructor === Date) {
1274
+ return '"' +
1275
+ o.getUTCFullYear() + '-' +
1276
+ String("0" + (o.getUTCMonth() + 1)).slice(-2) + '-' +
1277
+ String("0" + o.getUTCDate()).slice(-2) + 'T' +
1278
+ String("0" + o.getUTCHours()).slice(-2) + ':' +
1279
+ String("0" + o.getUTCMinutes()).slice(-2) + ':' +
1280
+ String("0" + o.getUTCSeconds()).slice(-2) + '.' +
1281
+ String("00" + o.getUTCMilliseconds()).slice(-3) + 'Z"';
1282
+ }
1283
+ if(o.constructor === Array) {
1284
+ for(i = 0; i < o.length; i++) {
1285
+ tmp.push( $.vakata.json.encode(o[i]) || "null" );
1286
+ }
1287
+ return "[" + tmp.join(",") + "]";
1288
+ }
1289
+
1290
+ $.each(o, function (i, v) {
1291
+ if($.isFunction(v)) { return true; }
1292
+ i = typeof i === "number" ? '"' + i + '"' : _quote(i);
1293
+ v = $.vakata.json.encode(v);
1294
+ tmp.push(i + ":" + v);
1295
+ });
1296
+ return "{" + tmp.join(", ") + "}";
1297
+ }
1298
+ },
1299
+ /*
1300
+ Function: $.vakata.json.decode
1301
+ Exists for consistency and is a simple wrapper for jQuery.parseJSON.
1302
+
1303
+ Parameters:
1304
+ json - the string to be decoded
1305
+
1306
+ Returns:
1307
+ Same as jQuery.parseJSON
1308
+ */
1309
+ decode : function (json) {
1310
+ return $.parseJSON(json);
1311
+ }
1312
+ };
1313
+ })(jQuery);
1314
+
1315
+ /*
1316
+ Group: Cookie
1317
+ A copy of the jQuery cookie plugin.
1318
+ */
1319
+ (function ($) {
1320
+ /*
1321
+ Function: $.vakata.cookie
1322
+ A function for getting and setting cookies.
1323
+
1324
+ Parameters:
1325
+ Same as the original plugin
1326
+
1327
+ Returns:
1328
+ string - the encoded data
1329
+ */
1330
+ $.vakata.cookie = function (key, value, options) {
1331
+ var days, t, result, decode;
1332
+ if (arguments.length > 1 && String(value) !== "[object Object]") {
1333
+ options = $.extend({}, options);
1334
+ if(value === null || value === undefined) { options.expires = -1; }
1335
+ if(typeof options.expires === 'number') { days = options.expires; t = options.expires = new Date(); t.setDate(t.getDate() + days); }
1336
+ value = String(value);
1337
+ return (document.cookie = [
1338
+ encodeURIComponent(key), '=',
1339
+ options.raw ? value : encodeURIComponent(value),
1340
+ options.expires ? '; expires=' + options.expires.toUTCString() : '',
1341
+ options.path ? '; path=' + options.path : '',
1342
+ options.domain ? '; domain=' + options.domain : '',
1343
+ options.secure ? '; secure' : ''
1344
+ ].join(''));
1345
+ }
1346
+ options = value || {};
1347
+ decode = options.raw ? function (s) { return s; } : decodeURIComponent;
1348
+ return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
1349
+ };
1350
+ })(jQuery);
1351
+
1352
+ /*
1353
+ Group: LocalStorage
1354
+ Functions for dealing with localStorage with fallback to userData or cookies. A slight modification of jstorage.
1355
+ */
1356
+
1357
+ (function ($) {
1358
+ var _storage = {},
1359
+ _storage_service = {jStorage:"{}"},
1360
+ _storage_elm = null,
1361
+ _storage_size = 0,
1362
+ json_encode = $.vakata.json.encode,
1363
+ json_decode = $.vakata.json.decode,
1364
+ _backend = false,
1365
+ _ttl_timeout = false;
1366
+
1367
+ function _init() {
1368
+ var localStorageReallyWorks = false;
1369
+ if("localStorage" in window){
1370
+ try {
1371
+ window.localStorage.setItem('_tmptest', 'tmpval');
1372
+ localStorageReallyWorks = true;
1373
+ window.localStorage.removeItem('_tmptest');
1374
+ } catch(BogusQuotaExceededErrorOnIos5) {
1375
+ // Thanks be to iOS5 Private Browsing mode which throws
1376
+ // QUOTA_EXCEEDED_ERRROR DOM Exception 22.
1377
+ }
1378
+ }
1379
+
1380
+ if(localStorageReallyWorks){
1381
+ try {
1382
+ if(window.localStorage) {
1383
+ _storage_service = window.localStorage;
1384
+ _backend = "localStorage";
1385
+ }
1386
+ } catch(E3) {/* Firefox fails when touching localStorage and cookies are disabled */}
1387
+ }
1388
+ else if("globalStorage" in window) {
1389
+ try {
1390
+ if(window.globalStorage) {
1391
+ _storage_service = window.globalStorage[window.location.hostname];
1392
+ _backend = "globalStorage";
1393
+ }
1394
+ } catch(E4) {/* Firefox fails when touching localStorage and cookies are disabled */}
1395
+ }
1396
+ else {
1397
+ _storage_elm = document.createElement('link');
1398
+ if(_storage_elm.addBehavior) {
1399
+ _storage_elm.style.behavior = 'url(#default#userData)';
1400
+ document.getElementsByTagName('head')[0].appendChild(_storage_elm);
1401
+ try {
1402
+ _storage_elm.load("jStorage");
1403
+ var data = "{}";
1404
+ data = _storage_elm.getAttribute("jStorage");
1405
+ _storage_service.jStorage = data;
1406
+ _backend = "userDataBehavior";
1407
+ } catch(E5) {}
1408
+ }
1409
+ if(
1410
+ !_backend && (
1411
+ !!$.vakata.cookie('__vjstorage') ||
1412
+ ($.vakata.cookie('__vjstorage', '{}', { 'expires' : 365 }) && $.vakata.cookie('__vjstorage') === '{}')
1413
+ )
1414
+ ) {
1415
+ _storage_elm = null;
1416
+ _storage_service.jStorage = $.vakata.cookie('__vjstorage');
1417
+ _backend = "cookie";
1418
+ }
1419
+
1420
+ if(!_backend) {
1421
+ _storage_elm = null;
1422
+ return;
1423
+ }
1424
+ }
1425
+ _load_storage();
1426
+ _handleTTL();
1427
+ }
1428
+
1429
+ function _load_storage() {
1430
+ if(_storage_service.jStorage) {
1431
+ try {
1432
+ _storage = json_decode(String(_storage_service.jStorage));
1433
+ } catch(E6) { _storage_service.jStorage = "{}"; }
1434
+ } else {
1435
+ _storage_service.jStorage = "{}";
1436
+ }
1437
+ _storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0;
1438
+ }
1439
+
1440
+ function _save() {
1441
+ try {
1442
+ _storage_service.jStorage = json_encode(_storage);
1443
+ if(_backend === 'userDataBehavior') {
1444
+ _storage_elm.setAttribute("jStorage", _storage_service.jStorage);
1445
+ _storage_elm.save("jStorage");
1446
+ }
1447
+ if(_backend === 'cookie') {
1448
+ $.vakata.cookie('__vjstorage', _storage_service.jStorage, { 'expires' : 365 });
1449
+ }
1450
+ _storage_size = _storage_service.jStorage?String(_storage_service.jStorage).length:0;
1451
+ } catch(E7) { /* probably cache is full, nothing is saved this way*/ }
1452
+ }
1453
+
1454
+ function _checkKey(key) {
1455
+ if(!key || (typeof key !== "string" && typeof key !== "number")){
1456
+ throw new TypeError('Key name must be string or numeric');
1457
+ }
1458
+ if(key === "__jstorage_meta") {
1459
+ throw new TypeError('Reserved key name');
1460
+ }
1461
+ return true;
1462
+ }
1463
+
1464
+ function _handleTTL() {
1465
+ var curtime = +new Date(),
1466
+ i,
1467
+ TTL,
1468
+ nextExpire = Infinity,
1469
+ changed = false;
1470
+
1471
+ if(_ttl_timeout !== false) {
1472
+ clearTimeout(_ttl_timeout);
1473
+ }
1474
+ if(!_storage.__jstorage_meta || typeof _storage.__jstorage_meta.TTL !== "object"){
1475
+ return;
1476
+ }
1477
+ TTL = _storage.__jstorage_meta.TTL;
1478
+ for(i in TTL) {
1479
+ if(TTL.hasOwnProperty(i)) {
1480
+ if(TTL[i] <= curtime) {
1481
+ delete TTL[i];
1482
+ delete _storage[i];
1483
+ changed = true;
1484
+ }
1485
+ else if(TTL[i] < nextExpire) {
1486
+ nextExpire = TTL[i];
1487
+ }
1488
+ }
1489
+ }
1490
+
1491
+ // set next check
1492
+ if(nextExpire !== Infinity) {
1493
+ _ttl_timeout = setTimeout(_handleTTL, nextExpire - curtime);
1494
+ }
1495
+ // save changes
1496
+ if(changed) {
1497
+ _save();
1498
+ }
1499
+ }
1500
+
1501
+ /*
1502
+ Variable: $.vakata.storage
1503
+ *object* holds all storage related functions and properties.
1504
+ */
1505
+ $.vakata.storage = {
1506
+ /*
1507
+ Variable: $.vakata.storage.version
1508
+ *string* the version of jstorage used
1509
+ */
1510
+ version: "0.1.6.1",
1511
+ /*
1512
+ Function: $.vakata.storage.set
1513
+ Set a key to a value
1514
+
1515
+ Parameters:
1516
+ key - the key
1517
+ value - the value
1518
+
1519
+ Returns:
1520
+ _value_
1521
+ */
1522
+ set : function (key, value) {
1523
+ _checkKey(key);
1524
+ _storage[key] = value;
1525
+ _save();
1526
+ return value;
1527
+ },
1528
+ /*
1529
+ Function: $.vakata.storage.get
1530
+ Get a value by key.
1531
+
1532
+ Parameters:
1533
+ key - the key
1534
+ def - the value to return if _key_ is not found
1535
+
1536
+ Returns:
1537
+ The found value, _def_ if key not found or _null_ if _def_ is not supplied.
1538
+ */
1539
+ get : function (key, def) {
1540
+ _checkKey(key);
1541
+ if(key in _storage){
1542
+ return _storage[key];
1543
+ }
1544
+ return typeof(def) === 'undefined' ? null : def;
1545
+ },
1546
+ /*
1547
+ Function: $.vakata.storage.del
1548
+ Remove a key.
1549
+
1550
+ Parameters:
1551
+ key - the key
1552
+
1553
+ Returns:
1554
+ *boolean*
1555
+ */
1556
+ del : function (key) {
1557
+ _checkKey(key);
1558
+ if(key in _storage) {
1559
+ delete _storage[key];
1560
+
1561
+ if(_storage.__jstorage_meta && typeof _storage.__jstorage_meta.TTL === "object" && key in _storage.__jstorage_meta.TTL) {
1562
+ delete _storage.__jstorage_meta.TTL[key];
1563
+ }
1564
+ _save();
1565
+ return true;
1566
+ }
1567
+ return false;
1568
+ },
1569
+
1570
+ setTTL: function(key, ttl){
1571
+ var curtime = +new Date();
1572
+
1573
+ _checkKey(key);
1574
+ ttl = Number(ttl) || 0;
1575
+ if(key in _storage){
1576
+ if(!_storage.__jstorage_meta){
1577
+ _storage.__jstorage_meta = {};
1578
+ }
1579
+ if(!_storage.__jstorage_meta.TTL) {
1580
+ _storage.__jstorage_meta.TTL = {};
1581
+ }
1582
+ if(ttl > 0) {
1583
+ _storage.__jstorage_meta.TTL[key] = curtime + ttl;
1584
+ }
1585
+ else {
1586
+ delete _storage.__jstorage_meta.TTL[key];
1587
+ }
1588
+ _save();
1589
+ _handleTTL();
1590
+ return true;
1591
+ }
1592
+ return false;
1593
+ },
1594
+
1595
+ /*
1596
+ Function: $.vakata.storage.flush
1597
+ Empty the storage.
1598
+
1599
+ Returns:
1600
+ _true_
1601
+ */
1602
+ flush : function(){
1603
+ _storage = {};
1604
+ _save();
1605
+ // try{ window.localStorage.clear(); } catch(E8) { }
1606
+ return true;
1607
+ },
1608
+ /*
1609
+ Function: $.vakata.storage.storageObj
1610
+ Get a read only copy of the whole storage.
1611
+
1612
+ Returns:
1613
+ *object*
1614
+ */
1615
+ storageObj : function(){
1616
+ function F() {}
1617
+ F.prototype = _storage;
1618
+ return new F();
1619
+ },
1620
+ /*
1621
+ Function: $.vakata.storage.index
1622
+ Get an array of all the set keys in the storage.
1623
+
1624
+ Returns:
1625
+ *array*
1626
+ */
1627
+ index : function(){
1628
+ var index = [], i;
1629
+ $.each(_storage, function (i, v) { if(i !== "__jstorage_meta") { index.push(i); } });
1630
+ return index;
1631
+ },
1632
+ /*
1633
+ Function: $.vakata.storage.storageSize
1634
+ Get the size of all items in the storage in bytes.
1635
+
1636
+ Returns:
1637
+ *number*
1638
+ */
1639
+ storageSize : function(){
1640
+ return _storage_size;
1641
+ },
1642
+ /*
1643
+ Function: $.vakata.storage.currentBackend
1644
+ Get the current backend used.
1645
+
1646
+ Returns:
1647
+ *string*
1648
+ */
1649
+ currentBackend : function(){
1650
+ return _backend;
1651
+ },
1652
+ /*
1653
+ Function: $.vakata.storage.storageAvailable
1654
+ See if storage functionality is available.
1655
+
1656
+ Returns:
1657
+ *boolean*
1658
+ */
1659
+ storageAvailable : function(){
1660
+ return !!_backend;
1661
+ }
1662
+ };
1663
+ _init();
1664
+ })(jQuery);
1665
+
1666
+ /*
1667
+ Group: PrettyDate
1668
+ Modifies time elements to a more human readable value. Taken from: https://github.com/zachleat/Humane-Dates/blob/master/src/humane.js
1669
+ */
1670
+ (function ($) {
1671
+ /*
1672
+ Variable: $.vakata.pretty_date
1673
+ *object* holds all pretty-date related functions and properties.
1674
+ */
1675
+ $.vakata.pretty_date = {
1676
+ /*
1677
+ Variable: $.vakata.pretty_date.lang
1678
+ *object* the localization to use.
1679
+ */
1680
+ lang : {
1681
+ ago: 'Ago',
1682
+ from: 'From Now',
1683
+ now: 'Just Now',
1684
+ minute: 'Minute',
1685
+ minutes: 'Minutes',
1686
+ hour: 'Hour',
1687
+ hours: 'Hours',
1688
+ day: 'Day',
1689
+ days: 'Days',
1690
+ week: 'Week',
1691
+ weeks: 'Weeks',
1692
+ month: 'Month',
1693
+ months: 'Months',
1694
+ year: 'Year',
1695
+ years: 'Years'
1696
+ },
1697
+ /*
1698
+ Function: $.vakata.pretty_date.parse
1699
+ Parses the difference between to dates to a human readable string.
1700
+
1701
+ Parameters:
1702
+ date - the date to calculate from (а string in this YYYY-MM-DDTHH:MM:SSZ format - UTC)
1703
+ comareTo - the date to compare to (as date), if left empty the current date is used
1704
+
1705
+ Returns:
1706
+ *mixed* - the formatted string on success or _null_ on error
1707
+ */
1708
+ parse : function (date, compareTo) {
1709
+ // remove the timezone (always use gmdate on server side)
1710
+ date = new Date(date.replace(/-/g,"/").replace(/[TZ]/g," ").replace(/\+\d\d\:\d\d$/,''));
1711
+ compareTo = compareTo || new Date();
1712
+ var lang = $.vakata.pretty_date.lang,
1713
+ formats = [
1714
+ [60, lang.now],
1715
+ [3600, lang.minute, lang.minutes, 60], // 60 minutes, 1 minute
1716
+ [86400, lang.hour, lang.hours, 3600], // 24 hours, 1 hour
1717
+ [604800, lang.day, lang.days, 86400], // 7 days, 1 day
1718
+ [2628000, lang.week, lang.weeks, 604800], // ~1 month, 1 week
1719
+ [31536000, lang.month, lang.months, 2628000], // 1 year, ~1 month
1720
+ [Infinity, lang.year, lang.years, 31536000] // Infinity, 1 year
1721
+ ],
1722
+ seconds = (compareTo - date + compareTo.getTimezoneOffset() * 60000) / 1000,
1723
+ normalize = function (val, single) {
1724
+ var margin = 0.1;
1725
+ if(val >= single && val <= single * (1+margin)) {
1726
+ return single;
1727
+ }
1728
+ return val;
1729
+ },
1730
+ token;
1731
+
1732
+ if(seconds < 0) {
1733
+ seconds = Math.abs(seconds);
1734
+ token = ' ' + lang.from;
1735
+ }
1736
+ else {
1737
+ token = ' ' + lang.ago;
1738
+ }
1739
+
1740
+ for(var i = 0, format = formats[0]; formats[i]; format = formats[++i]) {
1741
+ if(seconds < format[0]) {
1742
+ if(i === 0) {
1743
+ return format[1];
1744
+ }
1745
+ var val = Math.ceil(normalize(seconds, format[3]) / (format[3]));
1746
+ return val +
1747
+ ' ' +
1748
+ (val !== 1 ? format[2] : format[1]) +
1749
+ (i > 0 ? token : '');
1750
+ }
1751
+ }
1752
+ },
1753
+ /*
1754
+ Function: $.vakata.pretty_date.init
1755
+ Parses all time elements in the document and keeps reparsing them every few seconds.
1756
+
1757
+ Parameters:
1758
+ i - the interval for reparsing (in milliseconds). Default is 60000.
1759
+ format - the format to use, example: _Published %{s}._. Default is _%{s}_.
1760
+ */
1761
+ init : function (i, format) {
1762
+ $("time, [datetime]").vakata_pretty_date(format);
1763
+ setInterval(function(){ $("time, [datetime]").vakata_pretty_date(format); }, i || 60000);
1764
+ }
1765
+ };
1766
+ /*
1767
+ Function: $().vakata_pretty_date
1768
+ Sets the HTML of every element to the parsed difference of its _datetime_ attribute and the compare parameter.
1769
+
1770
+ Parameters:
1771
+ format - makes it possible to modify the parsed string, example: _Published %{s}._. Default is _%{s}_.
1772
+ compare - the date to compare to. Default is the current date.
1773
+ */
1774
+ $.fn.vakata_pretty_date = function (format, compare) {
1775
+ if(!format) { format = '%{s}'; }
1776
+ return this.each(function() {
1777
+ var $t = jQuery(this),
1778
+ date = $.vakata.pretty_date.parse($t.attr('datetime'), compare);
1779
+ if(date) {
1780
+ date = format.replace('%{s}', date);
1781
+ if($t.html() !== date) {
1782
+ $t.html(date);
1783
+ }
1784
+ }
1785
+ });
1786
+ };
1787
+ })(jQuery);
1788
+
1789
+ /*
1790
+ Group: Selection
1791
+ Selection related functions
1792
+ */
1793
+ (function ($) {
1794
+ /*
1795
+ Variable: $.vakata.selection
1796
+ *object* holds all selection related functions and properties.
1797
+ */
1798
+ $.vakata.selection = {
1799
+ /*
1800
+ Function: $.vakata.selection.get
1801
+ Gets the current selection.
1802
+
1803
+ Parameters:
1804
+ as_text - a boolean - if set to _true_ selection is returned as text, otherwise as HTML
1805
+
1806
+ Returns:
1807
+ *string* - the current selection
1808
+ */
1809
+ get : function (as_text) {
1810
+ if(window.getSelection) {
1811
+ if(as_text) {
1812
+ return window.getSelection().toString();
1813
+ }
1814
+ var userSelection = window.getSelection(),
1815
+ range = userSelection.getRangeAt && userSelection.rangeCount ? userSelection.getRangeAt(0) : document.createRange(),
1816
+ div = document.createElement('div');
1817
+ if(!userSelection.getRangeAt) {
1818
+ range.setStart(userSelection.anchorNode, userSelection.anchorOffset);
1819
+ range.setEnd(userSelection.focusNode, userSelection.focusOffset);
1820
+ }
1821
+ div.appendChild(range.cloneContents());
1822
+ return div.innerHTML;
1823
+ }
1824
+ if(document.selection) {
1825
+ return document.selection.createRange()[ as_text ? 'text' : 'htmlText' ];
1826
+ }
1827
+ return '';
1828
+ },
1829
+ /*
1830
+ Function: $.vakata.selection.elm_get
1831
+ Gets the selection inside an input element or textarea.
1832
+
1833
+ Parameters:
1834
+ e - the actual DOM element or the ID of the element
1835
+
1836
+ Returns:
1837
+ *object* - the current selection (start, end, length, text)
1838
+ */
1839
+ elm_get : function (e) {
1840
+ e = typeof e === 'string' ? document.getElementById(e) : e;
1841
+ if(e.jquery) { e = e.get(0); }
1842
+ if('selectionStart' in e) { // Mozilla and DOM 3.0
1843
+ return {
1844
+ 'start' : e.selectionStart,
1845
+ 'end' : e.selectionEnd,
1846
+ 'length' : (e.selectionEnd - e.selectionStart),
1847
+ 'text' : e.value.substr(e.selectionStart, (e.selectionEnd - e.selectionStart))
1848
+ };
1849
+ }
1850
+ else if(document.selection) { // IE
1851
+ e.focus();
1852
+ var tr0 = document.selection.createRange(),
1853
+ tr1 = false,
1854
+ tr2 = false,
1855
+ len, text_whole, the_start, the_end;
1856
+ if(tr0 && tr0.parentElement() === e) {
1857
+ len = e.value.length;
1858
+ text_whole = e.value.replace(/\r\n/g, "\n");
1859
+
1860
+ tr1 = e.createTextRange();
1861
+ tr1.moveToBookmark(tr0.getBookmark());
1862
+ tr2 = e.createTextRange();
1863
+ tr2.collapse(false);
1864
+
1865
+ if(tr1.compareEndPoints("StartToEnd", tr2) > -1) {
1866
+ the_start = the_end = len;
1867
+ }
1868
+ else {
1869
+ the_start = -tr1.moveStart("character", -len);
1870
+ the_start += text_whole.slice(0, the_start).split("\n").length - 1;
1871
+ if (tr1.compareEndPoints("EndToEnd", tr2) > -1) {
1872
+ the_end = len;
1873
+ } else {
1874
+ the_end = -tr1.moveEnd("character", -len);
1875
+ the_end += text_whole.slice(0, the_end).split("\n").length - 1;
1876
+ }
1877
+ }
1878
+ text_whole = e.value.slice(the_start, the_end);
1879
+ return {
1880
+ 'start' : the_start,
1881
+ 'end' : the_end,
1882
+ 'length' : text_whole.length,
1883
+ 'text' : text_whole
1884
+ };
1885
+ }
1886
+ }
1887
+ else { // not supported
1888
+ return {
1889
+ 'start' : e.value.length,
1890
+ 'end' : e.value.length,
1891
+ 'length' : 0,
1892
+ 'text' : ''
1893
+ };
1894
+ }
1895
+ },
1896
+ /*
1897
+ Function: $.vakata.selection.elm_set
1898
+ Sets the selection inside an input element or textarea.
1899
+
1900
+ Parameters:
1901
+ e - the actual DOM element or the ID of the element
1902
+ beg - the char to start the selection
1903
+ end - the char to end the selection
1904
+
1905
+ Returns:
1906
+ *object* - the current selection (start, end, length, text)
1907
+ */
1908
+ elm_set : function (e, beg, end) {
1909
+ e = typeof e === 'string' ? document.getElementById(e) : e;
1910
+ if(e.jquery) { e = e.get(0); }
1911
+ if('selectionStart' in e) { // Mozilla and DOM 3.0
1912
+ e.focus();
1913
+ e.selectionStart = beg;
1914
+ e.selectionEnd = end;
1915
+ }
1916
+ else if(document.selection) { // IE
1917
+ e.focus();
1918
+ var tr = e.createTextRange(),
1919
+ tx = e.value.replace(/\r\n/g, "\n");
1920
+
1921
+ beg -= tx.slice(0, beg).split("\n").length - 1;
1922
+ end -= tx.slice(0, end).split("\n").length - 1;
1923
+
1924
+ tr.collapse(true);
1925
+ tr.moveEnd('character', end);
1926
+ tr.moveStart('character', beg);
1927
+ tr.select();
1928
+ }
1929
+ return $.vakata.selection.elm_get(e);
1930
+ },
1931
+ /*
1932
+ Function: $.vakata.selection.elm_replace
1933
+ Replace the selection inside an input element or textarea.
1934
+
1935
+ Parameters:
1936
+ e - the actual DOM element or the ID of the element
1937
+ replace - the string to replace the selection with
1938
+
1939
+ Returns:
1940
+ *object* - the current selection (start, end, length, text)
1941
+ */
1942
+ elm_replace : function (e, replace) {
1943
+ e = typeof e === 'string' ? document.getElementById(e) : e;
1944
+ if(e.jquery) { e = e.get(0); }
1945
+ var sel = $.vakata.selection.elm_get(e),
1946
+ beg = sel.start,
1947
+ end = beg + replace.length;
1948
+ e.value = e.value.substr(0, beg) + replace + e.value.substr(sel.end, e.value.length);
1949
+ $.vakata.selection.elm_set(e, beg, end);
1950
+ return {
1951
+ 'start' : beg,
1952
+ 'end' : end,
1953
+ 'length' : replace.length,
1954
+ 'text' : replace
1955
+ };
1956
+ },
1957
+ /*
1958
+ Function: $.vakata.selection.elm_get_caret
1959
+ Returns the caret position in the element.
1960
+
1961
+ Parameters:
1962
+ e - the actual DOM element or the ID of the element
1963
+
1964
+ Returns:
1965
+ *number* - the current caret position
1966
+ */
1967
+ elm_get_caret : function (e) {
1968
+ return $.vakata.selection.elm_get(e).end;
1969
+ },
1970
+ /*
1971
+ Function: $.vakata.selection.elm_set_caret
1972
+ Sets the caret position in the element.
1973
+
1974
+ Parameters:
1975
+ e - the actual DOM element or the ID of the element
1976
+ pos - the position to move the caret to
1977
+
1978
+ Returns:
1979
+ *object* - the current selection
1980
+ */
1981
+ elm_set_caret : function (e, pos) {
1982
+ return $.vakata.selection.elm_set(e, pos, pos);
1983
+ },
1984
+ /*
1985
+ Function: $.vakata.selection.elm_get_caret_position
1986
+ Returns the caret position in pixels relative to the element.
1987
+
1988
+ Parameters:
1989
+ e - the actual DOM element or the ID of the element
1990
+
1991
+ Returns:
1992
+ *object* - the current position (with _left_ and _top_ values)
1993
+ */
1994
+ elm_get_caret_position : function (e) {
1995
+ e = typeof e === 'string' ? document.getElementById(e) : e;
1996
+ if(e.jquery) { e = e.get(0); }
1997
+ var p = $.vakata.selection.elm_get_caret(e),
1998
+ s = e.value.substring(0, p).replace(/&/g,'&amp;').replace(/</ig,'&lt;').replace(/>/ig,'&gt;').replace(/\r/g, '').replace(/\t/g,'&#10;').replace(/\n/ig, '<br />'),
1999
+ b = $.vakata.get_scrollbar_width(),
2000
+ w = $(e).width(),
2001
+ h = $(e).height();
2002
+ if(e.scrollHeight > h) { w -= b; }
2003
+ if(e.scrollWidth > w) { h -= b; }
2004
+ e = $(e);
2005
+ e = $('<div />').html(s).css({
2006
+ 'background': 'red',
2007
+ 'width' : w + 'px',
2008
+ 'height' : 'auto',
2009
+ 'position' : 'absolute',
2010
+ 'left' : '0px',
2011
+ 'top' : '-10000px',
2012
+
2013
+ 'fontSize' : e.css('fontSize'),
2014
+ 'fontFamily' : e.css('fontFamily'),
2015
+ 'fontWeight' : e.css('fontWeight'),
2016
+ 'fontVariant' : e.css('fontVariant'),
2017
+ 'fontStyle' : e.css('fontStyle'),
2018
+ 'textTransform' : e.css('textTransform'),
2019
+ 'lineHeight' : e.css('lineHeight'),
2020
+ 'whiteSpace' : 'pre-wrap'
2021
+ });
2022
+ e.append('<span class="caret">&nbsp;</span>').appendTo('body');
2023
+ s = e.find('span.caret');
2024
+ p = s.offset();
2025
+ p.top = p.top + 10000 + s.height();
2026
+ e.remove();
2027
+ return p;
2028
+ }
2029
+ };
2030
+ })(jQuery);
2031
+
2032
+
2033
+
2034
+ (function ($) {
2035
+ /*
2036
+ Function: $.vakata_highlight
2037
+ Hightlight words in the matched elements
2038
+
2039
+ Parameters:
2040
+ settings - if a string is passed, it is used to search and highlight, if an array of strings is passed, each string is highlighted, you can also pass an object, containing a _words_ string or array, a _color_ string or array, a _css_class_ string.
2041
+ */
2042
+ $.fn.vakata_highlight = function (settings) {
2043
+ var _return = this;
2044
+ if(typeof settings === 'string') {
2045
+ settings = [ settings ];
2046
+ }
2047
+ if($.isArray(settings)) {
2048
+ settings = { 'words' : settings };
2049
+ }
2050
+ settings = $.extend(true, {}, { 'css_class' : 'vakata-highlight', 'words' : [], 'color' : '#99ccff' }, settings);
2051
+ if(settings.words.length) {
2052
+ this.each(function () {
2053
+ var t = $(this);
2054
+ $.each(settings.words, function (i,v) {
2055
+ var color = false;
2056
+ if(typeof settings.color === 'string') {
2057
+ color = settings.color;
2058
+ }
2059
+ if($.isArray(settings.color) && typeof settings.color[i] === 'string') {
2060
+ color = settings.color[i];
2061
+ }
2062
+ t
2063
+ .find(':vakata_icontains("' + v.replace(/\"/ig,'') + '")')
2064
+ .filter('strong, span, li, p, h1, h2, h3, h4, h5, h6, div, u, em, i, dt, dd')
2065
+ .contents()
2066
+ .filter(function() { return this.nodeType === 3; })
2067
+ .each(function () {
2068
+ if(this.nodeValue.toLowerCase().indexOf(v.toLowerCase()) >= 0) {
2069
+ this.nodeValue = this.nodeValue.replace(new RegExp('(' + v.replace(/([\-.*+?\^${}()|\[\]\/\\])/g,"\\$1") + ')', 'ig'), '|{{{$1}}}|');
2070
+ var o = $(this).parent();
2071
+ o.html(o.html().replace(/\|\{\{\{/g,'<span class="' + settings.css_class + ' ' + settings.css_class + '-' + i + '" ' + ( typeof color === 'string' ? ' style="background:' + color + ';" ' : '' ) + '>').replace(/\}\}\}\|/g,'</span>'));
2072
+ }
2073
+ });
2074
+ });
2075
+ });
2076
+ }
2077
+ return _return;
2078
+ };
2079
+ })(jQuery);