cobweb 0.0.38 → 0.0.39

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 (160) hide show
  1. data/README.textile +1 -1
  2. data/lib/cobweb.rb +3 -1
  3. data/lib/cobweb_crawler.rb +98 -100
  4. data/lib/crawl_job.rb +3 -4
  5. data/lib/server.rb +98 -0
  6. data/lib/stats.rb +141 -64
  7. data/public/css/accordion.css +45 -0
  8. data/public/css/custom.css +13 -0
  9. data/public/css/datatable.css +189 -0
  10. data/public/css/datepicker.css +171 -0
  11. data/public/css/form-buttons.css +180 -0
  12. data/public/css/forms.css +489 -0
  13. data/public/css/jquery.fancybox-1.3.4.css +282 -0
  14. data/public/css/jquery.treeview.css +103 -0
  15. data/public/css/link-buttons.css +187 -0
  16. data/public/css/login.css +110 -0
  17. data/public/css/menu.css +156 -0
  18. data/public/css/messages.css +58 -0
  19. data/public/css/modalbox.css +63 -0
  20. data/public/css/statics.css +57 -0
  21. data/public/css/style.css +497 -0
  22. data/public/css/style_text.css +128 -0
  23. data/public/css/tabs.css +58 -0
  24. data/public/css/wysiwyg-editor.css +18 -0
  25. data/public/css/wysiwyg.css +149 -0
  26. data/public/css/wysiwyg.modal.css +69 -0
  27. data/public/gfx/back-menu.gif +0 -0
  28. data/public/gfx/back-submenu.gif +0 -0
  29. data/public/gfx/background.gif +0 -0
  30. data/public/gfx/box-hide.png +0 -0
  31. data/public/gfx/box-search.png +0 -0
  32. data/public/gfx/box-title.gif +0 -0
  33. data/public/gfx/code.gif +0 -0
  34. data/public/gfx/datepicker-arrows.gif +0 -0
  35. data/public/gfx/fancybox/blank.gif +0 -0
  36. data/public/gfx/fancybox/fancy_close.png +0 -0
  37. data/public/gfx/fancybox/fancy_loading.png +0 -0
  38. data/public/gfx/fancybox/fancy_nav_left.png +0 -0
  39. data/public/gfx/fancybox/fancy_nav_right.png +0 -0
  40. data/public/gfx/fancybox/fancy_title_left.png +0 -0
  41. data/public/gfx/fancybox/fancy_title_main.png +0 -0
  42. data/public/gfx/fancybox/fancy_title_over.png +0 -0
  43. data/public/gfx/fancybox/fancy_title_right.png +0 -0
  44. data/public/gfx/fancybox/fancybox-x.png +0 -0
  45. data/public/gfx/fancybox/fancybox.png +0 -0
  46. data/public/gfx/forms/date-next.gif +0 -0
  47. data/public/gfx/forms/date-prev.gif +0 -0
  48. data/public/gfx/forms/forms-checkbox.gif +0 -0
  49. data/public/gfx/forms/forms-date.gif +0 -0
  50. data/public/gfx/forms/forms-file.gif +0 -0
  51. data/public/gfx/forms/forms-input-big.gif +0 -0
  52. data/public/gfx/forms/forms-input-medium.gif +0 -0
  53. data/public/gfx/forms/forms-input-small.gif +0 -0
  54. data/public/gfx/forms/forms-input-xl.gif +0 -0
  55. data/public/gfx/forms/forms-radio.gif +0 -0
  56. data/public/gfx/forms/forms-selectbox-small.gif +0 -0
  57. data/public/gfx/forms/forms-selectbox.gif +0 -0
  58. data/public/gfx/forms/forms-textarea-big.gif +0 -0
  59. data/public/gfx/forms/forms-textarea-medium.gif +0 -0
  60. data/public/gfx/forms/forms-textarea-small.gif +0 -0
  61. data/public/gfx/forms/forms-textarea-xl.gif +0 -0
  62. data/public/gfx/icon-delete.png +0 -0
  63. data/public/gfx/icon-edit.png +0 -0
  64. data/public/gfx/icon-home.gif +0 -0
  65. data/public/gfx/img-delete.png +0 -0
  66. data/public/gfx/img-hover.png +0 -0
  67. data/public/gfx/img-zoom.png +0 -0
  68. data/public/gfx/jquery.wysiwyg.gif +0 -0
  69. data/public/gfx/label-icons.gif +0 -0
  70. data/public/gfx/label.gif +0 -0
  71. data/public/gfx/li-down.gif +0 -0
  72. data/public/gfx/li.gif +0 -0
  73. data/public/gfx/link-button-big.gif +0 -0
  74. data/public/gfx/link-button-medium.gif +0 -0
  75. data/public/gfx/link-button.gif +0 -0
  76. data/public/gfx/loading-2.gif +0 -0
  77. data/public/gfx/loading.gif +0 -0
  78. data/public/gfx/logo.png +0 -0
  79. data/public/gfx/modal-title.gif +0 -0
  80. data/public/gfx/photos/00.jpg +0 -0
  81. data/public/gfx/photos/01.jpg +0 -0
  82. data/public/gfx/photos/01xl.jpg +0 -0
  83. data/public/gfx/photos/02.jpg +0 -0
  84. data/public/gfx/photos/02xl.jpg +0 -0
  85. data/public/gfx/photos/03.jpg +0 -0
  86. data/public/gfx/photos/03xl.jpg +0 -0
  87. data/public/gfx/photos/04.jpg +0 -0
  88. data/public/gfx/photos/04xl.jpg +0 -0
  89. data/public/gfx/photos/05.jpg +0 -0
  90. data/public/gfx/photos/05xl.jpg +0 -0
  91. data/public/gfx/photos/06.jpg +0 -0
  92. data/public/gfx/photos/06xl.jpg +0 -0
  93. data/public/gfx/photos/07.jpg +0 -0
  94. data/public/gfx/photos/07xl.jpg +0 -0
  95. data/public/gfx/photos/08.jpg +0 -0
  96. data/public/gfx/photos/08xl.jpg +0 -0
  97. data/public/gfx/photos/09.jpg +0 -0
  98. data/public/gfx/photos/09xl.jpg +0 -0
  99. data/public/gfx/photos/10.jpg +0 -0
  100. data/public/gfx/photos/10xl.jpg +0 -0
  101. data/public/gfx/photos/11.jpg +0 -0
  102. data/public/gfx/photos/11xl.jpg +0 -0
  103. data/public/gfx/photos/12.jpg +0 -0
  104. data/public/gfx/photos/12xl.jpg +0 -0
  105. data/public/gfx/photos/13.jpg +0 -0
  106. data/public/gfx/photos/13xl.jpg +0 -0
  107. data/public/gfx/photos/14.jpg +0 -0
  108. data/public/gfx/photos/14xl.jpg +0 -0
  109. data/public/gfx/photos/15.jpg +0 -0
  110. data/public/gfx/photos/15xl.jpg +0 -0
  111. data/public/gfx/search-button.gif +0 -0
  112. data/public/gfx/search-input.gif +0 -0
  113. data/public/gfx/slider-button.gif +0 -0
  114. data/public/gfx/system-messages.gif +0 -0
  115. data/public/gfx/table-asc-arrow.gif +0 -0
  116. data/public/gfx/table-desc-arrow.gif +0 -0
  117. data/public/gfx/table-first.gif +0 -0
  118. data/public/gfx/table-last.gif +0 -0
  119. data/public/gfx/table-next.gif +0 -0
  120. data/public/gfx/table-number.gif +0 -0
  121. data/public/gfx/table-prev.gif +0 -0
  122. data/public/gfx/table-rows.gif +0 -0
  123. data/public/gfx/table-search.gif +0 -0
  124. data/public/gfx/table-thead.gif +0 -0
  125. data/public/gfx/tooltip.gif +0 -0
  126. data/public/gfx/treeview/ajax-loader.gif +0 -0
  127. data/public/gfx/treeview/file.gif +0 -0
  128. data/public/gfx/treeview/folder-closed.gif +0 -0
  129. data/public/gfx/treeview/folder.gif +0 -0
  130. data/public/gfx/treeview/minus.gif +0 -0
  131. data/public/gfx/treeview/plus.gif +0 -0
  132. data/public/gfx/treeview/treeview-default-line.gif +0 -0
  133. data/public/gfx/treeview/treeview-default.gif +0 -0
  134. data/public/js/controls/wysiwyg.image.js +284 -0
  135. data/public/js/controls/wysiwyg.link.js +210 -0
  136. data/public/js/controls/wysiwyg.table.js +151 -0
  137. data/public/js/customInput.jquery.js +68 -0
  138. data/public/js/excanvas.min.js +1 -0
  139. data/public/js/hoverIntent.js +84 -0
  140. data/public/js/inline.js +392 -0
  141. data/public/js/jquery-1.7.1.min.js +4 -0
  142. data/public/js/jquery-ui-select.js +522 -0
  143. data/public/js/jquery-ui-timepicker-addon.js +1299 -0
  144. data/public/js/jquery-ui.js +791 -0
  145. data/public/js/jquery.dataTables.js +7440 -0
  146. data/public/js/jquery.fancybox-1.3.4.js +1156 -0
  147. data/public/js/jquery.filestyle.mini.js +2 -0
  148. data/public/js/jquery.flot.js +2600 -0
  149. data/public/js/jquery.flot.resize.min.js +60 -0
  150. data/public/js/jquery.graphtable-0.2.js +179 -0
  151. data/public/js/jquery.tipsy.js +104 -0
  152. data/public/js/jquery.treeview.js +256 -0
  153. data/public/js/jquery.wysiwyg.js +2454 -0
  154. data/public/js/plugins/wysiwyg.rmFormat.js +348 -0
  155. data/public/js/superfish.js +121 -0
  156. data/public/js/supersubs.js +90 -0
  157. data/views/home.haml +54 -0
  158. data/views/layout.haml +89 -0
  159. data/views/statistics.haml +251 -71
  160. metadata +175 -22
@@ -0,0 +1,60 @@
1
+ /*
2
+ Flot plugin for automatically redrawing plots when the placeholder
3
+ size changes, e.g. on window resizes.
4
+
5
+ It works by listening for changes on the placeholder div (through the
6
+ jQuery resize event plugin) - if the size changes, it will redraw the
7
+ plot.
8
+
9
+ There are no options. If you need to disable the plugin for some
10
+ plots, you can just fix the size of their placeholders.
11
+ */
12
+
13
+
14
+ /* Inline dependency:
15
+ * jQuery resize event - v1.1 - 3/14/2010
16
+ * http://benalman.com/projects/jquery-resize-plugin/
17
+ *
18
+ * Copyright (c) 2010 "Cowboy" Ben Alman
19
+ * Dual licensed under the MIT and GPL licenses.
20
+ * http://benalman.com/about/license/
21
+ */
22
+ (function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this);
23
+
24
+
25
+ (function ($) {
26
+ var options = { }; // no options
27
+
28
+ function init(plot) {
29
+ function onResize() {
30
+ var placeholder = plot.getPlaceholder();
31
+
32
+ // somebody might have hidden us and we can't plot
33
+ // when we don't have the dimensions
34
+ if (placeholder.width() == 0 || placeholder.height() == 0)
35
+ return;
36
+
37
+ plot.resize();
38
+ plot.setupGrid();
39
+ plot.draw();
40
+ }
41
+
42
+ function bindEvents(plot, eventHolder) {
43
+ plot.getPlaceholder().resize(onResize);
44
+ }
45
+
46
+ function shutdown(plot, eventHolder) {
47
+ plot.getPlaceholder().unbind("resize", onResize);
48
+ }
49
+
50
+ plot.hooks.bindEvents.push(bindEvents);
51
+ plot.hooks.shutdown.push(shutdown);
52
+ }
53
+
54
+ $.plot.plugins.push({
55
+ init: init,
56
+ options: options,
57
+ name: 'resize',
58
+ version: '1.0'
59
+ });
60
+ })(jQuery);
@@ -0,0 +1,179 @@
1
+ (function($) {
2
+
3
+ $.fn.graphTable = function(_graphArgs,_flotArgs) {
4
+
5
+ var args = {
6
+
7
+ /*
8
+ * options for reading the table -- defaults will work in most cases except
9
+ * you'll want to override the default args.series if your series are in columns
10
+ *
11
+ * note that anywhere the word "index" is used, the count starts from 0 at
12
+ * the top left of the table
13
+ *
14
+ */
15
+ series: 'columns', // are the series in rows or columns?
16
+ labels: 0, // index of the cell in the series row/column that contains the label for the series
17
+ xaxis: 0, // index of the row/column (whatever args.series is) that contains the x values
18
+ firstSeries: 1, // index of the row/column containing the first series
19
+ lastSeries: null, // index of the row/column containing the last series; will use the last cell in the row/col if not set
20
+ dataStart: 1, // index of the first cell in the series containing data
21
+ dataEnd: null, // index of the last cell in the series containing data; will use the last cell in the row/col if not set
22
+
23
+ /* graph size and position */
24
+ position: 'after', // before the table, after the table, or replace the table
25
+ width: null, // set to null to use the width of the table
26
+ height: null, // set to null to use the height of the table
27
+ min: 0, // defaults to minimum y value in the table
28
+ max: 0, // defaults to maximum y value in the table
29
+
30
+ /* data transformation before plotting */
31
+ dataTransform: null, // function to run on cell contents before passing to flot; string -> string
32
+ labelTransform: null, // function to run on cell contents before passing to flot; string -> string
33
+ xaxisTransform: null, // function to run on cell contents before passing to flot; string -> string
34
+
35
+ //extra info added by me
36
+ colors: null
37
+ }
38
+
39
+ // override defaults with user args
40
+ $.extend(true,args,_graphArgs);
41
+
42
+ /* default to last cell in the row/col for
43
+ * lastSeries and dataEnd if they haven't been set yet */
44
+
45
+ // index of the row/column containing the last series
46
+ if (! args.lastSeries) {
47
+ args.lastSeries = (args.series == 'columns') ?
48
+ $('tr',$(this)).eq(args.labels).find('th,td').length - 1 :
49
+ $('tr',$(this)).length - 1;
50
+ }
51
+
52
+ // index of the last cell in the series containing data
53
+ if (! args.dataEnd) {
54
+ args.dataEnd = (args.series == 'rows') ?
55
+ $('tr',$(this)).eq(args.firstSeries).find('th,td').length - 1:
56
+ $('tr',$(this)).length - 1;
57
+ }
58
+
59
+ return $(this).each(function() {
60
+ // use local min/max for y of each graph, based on initial args
61
+ var $table = $(this);
62
+
63
+ // make sure the table is a table!
64
+ if (! $table.is('table')) { return; }
65
+
66
+ // if no height and width have been set, then set
67
+ // width and height based on the width and height of the table
68
+ if (! args.width) { args.width = $table.width(); }
69
+ if (! args.height) { args.height = $table.height(); }
70
+
71
+ var min = args.min;
72
+ var max = args.max;
73
+ var $rows = $('tr',$table);
74
+ var tableData = new Array();
75
+
76
+ switch (args.series) {
77
+ case 'rows':
78
+
79
+ var $xaxisRow = $rows.eq(args.xaxis);
80
+
81
+ // iterate over each of the rows in the series
82
+ for (i=args.firstSeries;i<=args.lastSeries;i++) {
83
+ var rowData = new Array();
84
+
85
+ $dataRow = $('tr',$table).eq(i);
86
+
87
+ // get the label for the whole row
88
+ var label = $('th,td',$dataRow).eq(args.labels).text();
89
+
90
+ if (args.labelTransform) { label = args.labelTransform(label); }
91
+
92
+ for (j=args.dataStart;j<=args.dataEnd;j++) {
93
+ var x = $('th,td',$xaxisRow).eq(j).text();
94
+ var y = $('th,td',$dataRow).eq(j).text();
95
+
96
+ if (args.dataTransform) { y = args.dataTransform(y); }
97
+ if (args.xaxisTransform) { x = args.xaxisTransform(x); }
98
+
99
+ test_x = parseFloat(x);
100
+ test_y = parseFloat(y);
101
+
102
+ if (test_y < min) { min = test_y; }
103
+ else if (test_y > max) { max = test_y; }
104
+
105
+ rowData[rowData.length] = [x,y];
106
+ }
107
+
108
+ tableData[tableData.length] = { label: label, data: rowData };
109
+
110
+ }
111
+
112
+ break;
113
+
114
+
115
+ case 'columns':
116
+ // iterate over each of the columns in the series
117
+ var $labelRow = $rows.eq(args.labels);
118
+
119
+ for (j=args.firstSeries;j<=args.lastSeries;j++) { // j designates the column
120
+ var colData = new Array();
121
+
122
+ var label = $labelRow.find('th,td').eq(j).text();
123
+ if (args.labelTransform) { label = args.labelTransform(label); }
124
+
125
+ for (i=args.dataStart;i<=args.dataEnd;i++) { // i designates the row
126
+ $cell = $rows.eq(i).find('th,td').eq(j);
127
+ var y = $cell.text();
128
+ var x = $rows.eq(i).find('th,td').eq(args.xaxis).text();
129
+
130
+ if (args.dataTransform) { y = args.dataTransform(y); }
131
+ if (args.xaxisTransform) { x = args.xaxisTransform(x); }
132
+
133
+ test_x = parseFloat(x);
134
+ test_y = parseFloat(y);
135
+
136
+ if (test_y < min) { min = test_y; }
137
+ else if (test_y > max) { max = test_y; }
138
+
139
+ colData[colData.length] = [x,y];
140
+ }
141
+
142
+ //changed/added this code
143
+ var series = {label: label, data: colData };
144
+ if (args.colors && args.colors[j-args.dataStart]){
145
+ series.color = args.colors[j-args.dataStart]
146
+ }
147
+ tableData[tableData.length] = series;
148
+
149
+
150
+ }
151
+
152
+ break;
153
+ }
154
+
155
+ switch (args.position) {
156
+ case 'after':
157
+ $div = $('<div class="flot-graph" />').insertAfter($table);
158
+ break;
159
+
160
+ case 'replace':
161
+ $div = $('<div class="flot-graph" />').insertAfter($table);
162
+ $table.remove();
163
+ break;
164
+
165
+ default:
166
+ $div = $('<div class="flot-graph" />').insertBefore($table);
167
+ break;
168
+ }
169
+
170
+ var flotArgs = { yaxis: { min: min, max: max }, title: 'foo' };
171
+
172
+ $div.width(args.width).height(args.height);
173
+ $.extend(true,flotArgs,_flotArgs);
174
+ $.plot($div, tableData, flotArgs);
175
+
176
+ });
177
+ };
178
+
179
+ })(jQuery);
@@ -0,0 +1,104 @@
1
+ (function($) {
2
+ $.fn.tipsy = function(options) {
3
+
4
+ options = $.extend({}, $.fn.tipsy.defaults, options);
5
+
6
+ return this.each(function() {
7
+
8
+ var opts = $.fn.tipsy.elementOptions(this, options);
9
+
10
+ $(this).hover(function() {
11
+
12
+ $.data(this, 'cancel.tipsy', true);
13
+
14
+ var tip = $.data(this, 'active.tipsy');
15
+ if (!tip) {
16
+ tip = $('<div class="tipsy"><div class="tipsy-inner"/></div>');
17
+ tip.css({position: 'absolute', zIndex: 100000});
18
+ $.data(this, 'active.tipsy', tip);
19
+ }
20
+
21
+ if ($(this).attr('title') || typeof($(this).attr('original-title')) != 'string') {
22
+ $(this).attr('original-title', $(this).attr('title') || '').removeAttr('title');
23
+ }
24
+
25
+ var title;
26
+ if (typeof opts.title == 'string') {
27
+ title = $(this).attr(opts.title == 'title' ? 'original-title' : opts.title);
28
+ } else if (typeof opts.title == 'function') {
29
+ title = opts.title.call(this);
30
+ }
31
+
32
+ tip.find('.tipsy-inner')[opts.html ? 'html' : 'text'](title || opts.fallback);
33
+
34
+ var pos = $.extend({}, $(this).offset(), {width: this.offsetWidth, height: this.offsetHeight});
35
+ tip.get(0).className = 'tipsy'; // reset classname in case of dynamic gravity
36
+ tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).appendTo(document.body);
37
+ var actualWidth = tip[0].offsetWidth, actualHeight = tip[0].offsetHeight;
38
+ var gravity = (typeof opts.gravity == 'function') ? opts.gravity.call(this) : opts.gravity;
39
+
40
+ switch (gravity.charAt(0)) {
41
+ case 'n':
42
+ tip.css({top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}).addClass('tipsy-north');
43
+ break;
44
+ case 's':
45
+ tip.css({top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}).addClass('tipsy-south');
46
+ break;
47
+ case 'e':
48
+ tip.css({top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}).addClass('tipsy-east');
49
+ break;
50
+ case 'w':
51
+ tip.css({top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}).addClass('tipsy-west');
52
+ break;
53
+ }
54
+
55
+ if (opts.fade) {
56
+ tip.css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: 1.0});
57
+ } else {
58
+ tip.css({visibility: 'visible'});
59
+ }
60
+
61
+ }, function() {
62
+ $.data(this, 'cancel.tipsy', false);
63
+ var self = this;
64
+ setTimeout(function() {
65
+ if ($.data(this, 'cancel.tipsy')) return;
66
+ var tip = $.data(self, 'active.tipsy');
67
+ if (opts.fade) {
68
+ tip.stop().fadeOut(function() { $(this).remove(); });
69
+ } else {
70
+ tip.remove();
71
+ }
72
+ }, 100);
73
+
74
+ });
75
+
76
+ });
77
+
78
+ };
79
+
80
+ // Overwrite this method to provide options on a per-element basis.
81
+ // For example, you could store the gravity in a 'tipsy-gravity' attribute:
82
+ // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' });
83
+ // (remember - do not modify 'options' in place!)
84
+ $.fn.tipsy.elementOptions = function(ele, options) {
85
+ return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
86
+ };
87
+
88
+ $.fn.tipsy.defaults = {
89
+ fade: false,
90
+ fallback: '',
91
+ gravity: 'n',
92
+ html: false,
93
+ title: 'title'
94
+ };
95
+
96
+ $.fn.tipsy.autoNS = function() {
97
+ return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n';
98
+ };
99
+
100
+ $.fn.tipsy.autoWE = function() {
101
+ return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w';
102
+ };
103
+
104
+ })(jQuery);
@@ -0,0 +1,256 @@
1
+ /*
2
+ * Treeview 1.5pre - jQuery plugin to hide and show branches of a tree
3
+ *
4
+ * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
5
+ * http://docs.jquery.com/Plugins/Treeview
6
+ *
7
+ * Copyright (c) 2007 Jörn Zaefferer
8
+ *
9
+ * Dual licensed under the MIT and GPL licenses:
10
+ * http://www.opensource.org/licenses/mit-license.php
11
+ * http://www.gnu.org/licenses/gpl.html
12
+ *
13
+ * Revision: $Id: jquery.treeview.js 5759 2008-07-01 07:50:28Z joern.zaefferer $
14
+ *
15
+ */
16
+
17
+ ;(function($) {
18
+
19
+ // TODO rewrite as a widget, removing all the extra plugins
20
+ $.extend($.fn, {
21
+ swapClass: function(c1, c2) {
22
+ var c1Elements = this.filter('.' + c1);
23
+ this.filter('.' + c2).removeClass(c2).addClass(c1);
24
+ c1Elements.removeClass(c1).addClass(c2);
25
+ return this;
26
+ },
27
+ replaceClass: function(c1, c2) {
28
+ return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
29
+ },
30
+ hoverClass: function(className) {
31
+ className = className || "hover";
32
+ return this.hover(function() {
33
+ $(this).addClass(className);
34
+ }, function() {
35
+ $(this).removeClass(className);
36
+ });
37
+ },
38
+ heightToggle: function(animated, callback) {
39
+ animated ?
40
+ this.animate({ height: "toggle" }, animated, callback) :
41
+ this.each(function(){
42
+ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
43
+ if(callback)
44
+ callback.apply(this, arguments);
45
+ });
46
+ },
47
+ heightHide: function(animated, callback) {
48
+ if (animated) {
49
+ this.animate({ height: "hide" }, animated, callback);
50
+ } else {
51
+ this.hide();
52
+ if (callback)
53
+ this.each(callback);
54
+ }
55
+ },
56
+ prepareBranches: function(settings) {
57
+ if (!settings.prerendered) {
58
+ // mark last tree items
59
+ this.filter(":last-child:not(ul)").addClass(CLASSES.last);
60
+ // collapse whole tree, or only those marked as closed, anyway except those marked as open
61
+ this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
62
+ }
63
+ // return all items with sublists
64
+ return this.filter(":has(>ul)");
65
+ },
66
+ applyClasses: function(settings, toggler) {
67
+ // TODO use event delegation
68
+ this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) {
69
+ // don't handle click events on children, eg. checkboxes
70
+ if ( this == event.target )
71
+ toggler.apply($(this).next());
72
+ }).add( $("a", this) ).hoverClass();
73
+
74
+ if (!settings.prerendered) {
75
+ // handle closed ones first
76
+ this.filter(":has(>ul:hidden)")
77
+ .addClass(CLASSES.expandable)
78
+ .replaceClass(CLASSES.last, CLASSES.lastExpandable);
79
+
80
+ // handle open ones
81
+ this.not(":has(>ul:hidden)")
82
+ .addClass(CLASSES.collapsable)
83
+ .replaceClass(CLASSES.last, CLASSES.lastCollapsable);
84
+
85
+ // create hitarea if not present
86
+ var hitarea = this.find("div." + CLASSES.hitarea);
87
+ if (!hitarea.length)
88
+ hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea);
89
+ hitarea.removeClass().addClass(CLASSES.hitarea).each(function() {
90
+ var classes = "";
91
+ $.each($(this).parent().attr("class").split(" "), function() {
92
+ classes += this + "-hitarea ";
93
+ });
94
+ $(this).addClass( classes );
95
+ })
96
+ }
97
+
98
+ // apply event to hitarea
99
+ this.find("div." + CLASSES.hitarea).click( toggler );
100
+ },
101
+ treeview: function(settings) {
102
+
103
+ settings = $.extend({
104
+ cookieId: "treeview"
105
+ }, settings);
106
+
107
+ if ( settings.toggle ) {
108
+ var callback = settings.toggle;
109
+ settings.toggle = function() {
110
+ return callback.apply($(this).parent()[0], arguments);
111
+ };
112
+ }
113
+
114
+ // factory for treecontroller
115
+ function treeController(tree, control) {
116
+ // factory for click handlers
117
+ function handler(filter) {
118
+ return function() {
119
+ // reuse toggle event handler, applying the elements to toggle
120
+ // start searching for all hitareas
121
+ toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
122
+ // for plain toggle, no filter is provided, otherwise we need to check the parent element
123
+ return filter ? $(this).parent("." + filter).length : true;
124
+ }) );
125
+ return false;
126
+ };
127
+ }
128
+ // click on first element to collapse tree
129
+ $("a:eq(0)", control).click( handler(CLASSES.collapsable) );
130
+ // click on second to expand tree
131
+ $("a:eq(1)", control).click( handler(CLASSES.expandable) );
132
+ // click on third to toggle tree
133
+ $("a:eq(2)", control).click( handler() );
134
+ }
135
+
136
+ // handle toggle event
137
+ function toggler() {
138
+ $(this)
139
+ .parent()
140
+ // swap classes for hitarea
141
+ .find(">.hitarea")
142
+ .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
143
+ .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
144
+ .end()
145
+ // swap classes for parent li
146
+ .swapClass( CLASSES.collapsable, CLASSES.expandable )
147
+ .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
148
+ // find child lists
149
+ .find( ">ul" )
150
+ // toggle them
151
+ .heightToggle( settings.animated, settings.toggle );
152
+ if ( settings.unique ) {
153
+ $(this).parent()
154
+ .siblings()
155
+ // swap classes for hitarea
156
+ .find(">.hitarea")
157
+ .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
158
+ .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
159
+ .end()
160
+ .replaceClass( CLASSES.collapsable, CLASSES.expandable )
161
+ .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
162
+ .find( ">ul" )
163
+ .heightHide( settings.animated, settings.toggle );
164
+ }
165
+ }
166
+ this.data("toggler", toggler);
167
+
168
+ function serialize() {
169
+ function binary(arg) {
170
+ return arg ? 1 : 0;
171
+ }
172
+ var data = [];
173
+ branches.each(function(i, e) {
174
+ data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
175
+ });
176
+ $.cookie(settings.cookieId, data.join(""), settings.cookieOptions );
177
+ }
178
+
179
+ function deserialize() {
180
+ var stored = $.cookie(settings.cookieId);
181
+ if ( stored ) {
182
+ var data = stored.split("");
183
+ branches.each(function(i, e) {
184
+ $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
185
+ });
186
+ }
187
+ }
188
+
189
+ // add treeview class to activate styles
190
+ this.addClass("treeview");
191
+
192
+ // prepare branches and find all tree items with child lists
193
+ var branches = this.find("li").prepareBranches(settings);
194
+
195
+ switch(settings.persist) {
196
+ case "cookie":
197
+ var toggleCallback = settings.toggle;
198
+ settings.toggle = function() {
199
+ serialize();
200
+ if (toggleCallback) {
201
+ toggleCallback.apply(this, arguments);
202
+ }
203
+ };
204
+ deserialize();
205
+ break;
206
+ case "location":
207
+ var current = this.find("a").filter(function() {
208
+ return this.href.toLowerCase() == location.href.toLowerCase();
209
+ });
210
+ if ( current.length ) {
211
+ // TODO update the open/closed classes
212
+ var items = current.addClass("selected").parents("ul, li").add( current.next() ).show();
213
+ if (settings.prerendered) {
214
+ // if prerendered is on, replicate the basic class swapping
215
+ items.filter("li")
216
+ .swapClass( CLASSES.collapsable, CLASSES.expandable )
217
+ .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
218
+ .find(">.hitarea")
219
+ .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
220
+ .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea );
221
+ }
222
+ }
223
+ break;
224
+ }
225
+
226
+ branches.applyClasses(settings, toggler);
227
+
228
+ // if control option is set, create the treecontroller and show it
229
+ if ( settings.control ) {
230
+ treeController(this, settings.control);
231
+ $(settings.control).show();
232
+ }
233
+
234
+ return this;
235
+ }
236
+ });
237
+
238
+ // classes used by the plugin
239
+ // need to be styled via external stylesheet, see first example
240
+ $.treeview = {};
241
+ var CLASSES = ($.treeview.classes = {
242
+ open: "open",
243
+ closed: "closed",
244
+ expandable: "expandable",
245
+ expandableHitarea: "expandable-hitarea",
246
+ lastExpandableHitarea: "lastExpandable-hitarea",
247
+ collapsable: "collapsable",
248
+ collapsableHitarea: "collapsable-hitarea",
249
+ lastCollapsableHitarea: "lastCollapsable-hitarea",
250
+ lastCollapsable: "lastCollapsable",
251
+ lastExpandable: "lastExpandable",
252
+ last: "last",
253
+ hitarea: "hitarea"
254
+ });
255
+
256
+ })(jQuery);