jstree-rails 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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);