sortable_nested_set 0.1.26 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,3 @@
1
- require 'sortable_element_for_nested_set'
2
- include SortableElementForNestedSet
3
-
4
1
  module SortableNestedSet
5
2
  def self.included(base)
6
3
  base.extend ClassMethods
@@ -8,146 +5,68 @@ module SortableNestedSet
8
5
 
9
6
  module ClassMethods
10
7
  def handles_sortable_nested_set
11
- handles_sorting_of_nested_set
12
-
13
8
  class_eval do
14
- define_method(:sns_category_controller) { controller_name }
15
9
  define_method(:sns_category_id_field) { "#{controller_name.singularize}_id" }
16
10
  define_method(:sns_category_class) { controller_name.classify.constantize }
17
- define_method(:sns_items_type) {sns_category_class.sns_items_type }
18
- define_method(:sns_item_class) {sns_items_type.to_s.classify.constantize }
11
+ define_method(:sns_items_type) { sns_category_class.sns_items_type }
12
+ define_method(:sns_item_class) { sns_items_type.to_s.classify.constantize }
19
13
  end
20
14
 
21
- include(SortableNestedSet::InstanceMethods)
15
+ include InstanceMethods
22
16
  end
23
17
  end
24
18
 
25
19
  module InstanceMethods
26
20
  def sns_add_subcategory
27
- redirect_to :controller => sns_category_controller, :action => :new, sns_category_id_field => params[:id]
21
+ redirect_to :action => :new, sns_category_id_field => params[:id]
28
22
  end
29
23
 
30
24
  def sns_add_item
31
25
  redirect_to :controller => sns_items_type, :action => :new, sns_category_id_field => params[:id]
32
26
  end
33
27
 
34
- def sns_sort_categories
35
- category = sns_category_class.find(params[:moved])
36
- new_pos = position_of(:moved).in_tree(:menu)
37
-
38
- # Ambiguous moves occur when a category is dropped outside the menu AND
39
- # a :root parameter is specified. In this case, move the element to the
40
- # :root category in the database and also put it at the end with javascript.
41
- ambiguous_move = nil
42
-
43
- begin
44
- category.transaction do
45
- if new_pos[:parent]
46
- category.move_to_child_of(new_pos[:parent])
47
- elsif params[:root].nil?
48
- category.move_to_root
49
- else
50
- root_id = params[:root].to_i
51
- ambiguous_move = params[:menu]['0']['id'] == params[:moved] ? :top : :bottom
52
-
53
- if ambiguous_move == :bottom
54
- category.move_to_child_of(params[:root])
55
- else
56
- category.move_to_left_of(sns_category_class.find(params[:root]).sns_subcategories.first)
57
- end
58
- end unless category.parent_id === new_pos[:parent]
28
+ def sns_sort
29
+ matches = params[:moved].match(/(\w+)_(\d+)$/)
30
+ moved_type = matches[1]
31
+ moved_id = matches[2].to_i
32
+ moved_parent = nil
33
+ tree = {} # category_id => [children of move_type]
59
34
 
60
- begin
61
- if new_pos[:move_to_right_of]
62
- category.move_to_right_of(new_pos[:move_to_right_of])
63
- else
64
- category.move_to_left_of(new_pos[:move_to_left_of])
65
- end
66
- rescue ActiveRecord::RecordNotFound
67
- # FIXME error raised when making first child
68
- end unless ambiguous_move
35
+ for node in params[:tree].scan(/(\w+)\[(\d+)\]=(\w+)/)
36
+ type = node[0]
37
+ next unless type == moved_type
69
38
 
70
- raise category.errors.full_messages.to_sentence unless category.valid?
71
- end
72
- rescue => err
73
- render :update do |page|
74
- page.alert err.message
75
- page.reload # TODO return to original location with javascript
76
- end
77
- else
78
- render :update do |page|
79
- page.assign :categoryElement, page.literal("$('category_#{category.id}')")
80
-
81
- if ambiguous_move
82
- page.assign :rootElement, page.literal("$('subcategories_#{root_id}')")
83
- page.remove "category_#{category.id}"
84
-
85
- # there is a placeholder at index 0
86
- page << (ambiguous_move == :top ?
87
- 'rootElement.insertBefore(categoryElement, rootElement.childElements()[1])' :
88
- 'rootElement.insert(categoryElement)')
39
+ id = node[1].to_i
40
+ parent = (node[2] == 'root') ? nil : node[2].to_i
89
41
 
90
- page.visual_effect 'highlight', "category_#{category.id}"
91
- else
92
- page.assign :elderSibling, page.literal('categoryElement.nextElementSibling')
93
- page.assign :parent, page.literal('categoryElement.parentNode')
42
+ moved_parent = parent if id == moved_id
94
43
 
95
- page << <<EOF
96
- if (elderSibling && elderSibling.hasClassName('placeholder')) {
97
- elderSibling.remove();
98
- parent.insertBefore(elderSibling, categoryElement);
99
- }
100
-
101
- /* WORKAROUND DEFECT: after dragdrop, z-index not abided by */
102
- categoryElement.style.removeProperty('z-index');
103
- EOF
104
- end
105
- end
44
+ tree[parent] ||= []
45
+ tree[parent] << id
106
46
  end
107
- end
108
47
 
109
- def sns_sort_items
110
- container = params.find { |key, val| key =~ /items_\d+/ }
111
-
112
- params[container.first].each_with_index do |id, index|
113
- category_id = container.first.match(/items_(\d+)/)[1]
114
- sns_item_class.update(id, sns_category_id_field => category_id, :position => index + 1)
115
- end if container
116
-
117
- render :update do |page|
118
- id = "item_#{params[:moved]}"
119
- page << "$('#{id}').style.removeProperty('z-index')"
48
+ if moved_type == sns_items_type.to_s.singularize
49
+ item = sns_item_class.find(moved_id)
50
+ item.remove_from_list
51
+ item.update_attribute(sns_category_id_field, moved_parent)
52
+ item.insert_at(tree[moved_parent].index(moved_id))
53
+ else
54
+ moved_type.classify.constantize.find(moved_id).move(moved_parent, tree[moved_parent])
120
55
  end
121
- end
122
56
 
123
- def sns_toggle
124
- render :update do |page|
125
- page["items_#{params[:id]}"].toggle
126
- page["subcategories_#{params[:id]}"].toggle
127
- page.replace_html "toggle_#{params[:id]}",
128
- :partial => 'sortable_nested_set/toggle',
129
- :locals => { :category_type => params[:category_type],
130
- :id => params[:id],
131
- :state => (params[:state] == :open ? :closed : :open) }
132
- end
57
+ render :nothing => true
133
58
  end
134
59
 
135
60
  def sns_destroy_category
136
61
  @category = sns_category_class.find(params[:id])
137
62
  @category.destroy
138
-
139
- render :update do |page|
140
- page["category_#{@category.id}"].remove
141
- end
63
+ render 'sortable_nested_set/sns_destroy_category'
142
64
  end
143
65
 
144
66
  def sns_destroy_item
145
67
  @item = sns_item_class.find(params[:id])
146
68
  @item.destroy
147
-
148
- render :update do |page|
149
- page["item_#{@item.id}"].remove
150
- end
69
+ render 'sortable_nested_set/sns_destroy_item'
151
70
  end
152
71
  end
153
72
  end
@@ -15,8 +15,7 @@ module ActionDispatch::Routing
15
15
  end
16
16
 
17
17
  collection do
18
- put :sns_sort_categories
19
- put :sns_sort_items
18
+ put :sns_sort
20
19
  end
21
20
  end
22
21
 
@@ -1,4 +1,4 @@
1
- require 'sortable_nested_set/engine' if defined? Rails && Rails::VERSION::MAJOR == 3
1
+ require 'sortable_nested_set/engine'
2
2
  require 'sortable_nested_set/acts_as_sortable_nested_set'
3
3
  require 'sortable_nested_set/handles_sortable_nested_set'
4
4
  require 'sortable_nested_set/routes'
Binary file
Binary file
Binary file
@@ -0,0 +1,10 @@
1
+ /**
2
+ * hoverIntent r5 // 2007.03.27 // jQuery 1.1.2
3
+ * <http://cherne.net/brian/resources/jquery.hoverIntent.html>
4
+ *
5
+ * @param f onMouseOver function || An object with configuration options
6
+ * @param g onMouseOut function || Nothing (use configuration options object)
7
+ * @return The object (aka "this") that called hoverIntent, and the event object
8
+ * @author Brian Cherne <brian@cherne.net>
9
+ */
10
+ (function($){$.fn.hoverIntent=function(f,g){var cfg={sensitivity:7,interval:100,timeout:0};cfg=$.extend(cfg,g?{over:f,out:g}:f);var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY;};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if((Math.abs(pX-cX)+Math.abs(pY-cY))<cfg.sensitivity){$(ob).unbind("mousemove",track);ob.hoverIntent_s=1;return cfg.over.apply(ob,[ev]);}else{pX=cX;pY=cY;ob.hoverIntent_t=setTimeout(function(){compare(ev,ob);},cfg.interval);}};var delay=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);ob.hoverIntent_s=0;return cfg.out.apply(ob,[ev]);};var handleHover=function(e){var p=(e.type=="mouseover"?e.fromElement:e.toElement)||e.relatedTarget;while(p&&p!=this){try{p=p.parentNode;}catch(e){p=this;}}if(p==this){return false;}var ev=jQuery.extend({},e);var ob=this;if(ob.hoverIntent_t){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);}if(e.type=="mouseover"){pX=ev.pageX;pY=ev.pageY;$(ob).bind("mousemove",track);if(ob.hoverIntent_s!=1){ob.hoverIntent_t=setTimeout(function(){compare(ev,ob);},cfg.interval);}}else{$(ob).unbind("mousemove",track);if(ob.hoverIntent_s==1){ob.hoverIntent_t=setTimeout(function(){delay(ev,ob);},cfg.timeout);}}};return this.mouseover(handleHover).mouseout(handleHover);};})(jQuery);
@@ -0,0 +1,291 @@
1
+ /*
2
+ * jQuery UI Nested Sortable 1.2.1
3
+ *
4
+ * Copyright 2010, Manuele J Sarfatti
5
+ *
6
+ * http://mjsarfatti.com/sandbox/nestedSortable
7
+ *
8
+ * Depends:
9
+ * jquery.ui.core.js 1.8+
10
+ * jquery.ui.widget.js 1.8+
11
+ * jquery.ui.sortable.js 1.8+
12
+ */
13
+ (function($) {
14
+
15
+ $.widget("ui.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
16
+
17
+ options: {
18
+ tabSize: 20,
19
+ disableNesting: 'ui-nestedSortable-no-nesting',
20
+ errorClass: 'ui-nestedSortable-error',
21
+ listType: 'ol'
22
+ },
23
+
24
+ _create: function(){
25
+ this.element.data('sortable', this.element.data('sortableTree'));
26
+ return $.ui.sortable.prototype._create.apply(this, arguments);
27
+ },
28
+
29
+ _mouseDrag: function(event) {
30
+
31
+ //Compute the helpers position
32
+ this.position = this._generatePosition(event);
33
+ this.positionAbs = this._convertPositionTo("absolute");
34
+
35
+ if (!this.lastPositionAbs) {
36
+ this.lastPositionAbs = this.positionAbs;
37
+ }
38
+
39
+ //Do scrolling
40
+ if(this.options.scroll) {
41
+ var o = this.options, scrolled = false;
42
+ if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
43
+
44
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
45
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
46
+ else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
47
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
48
+
49
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
50
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
51
+ else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
52
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
53
+
54
+ } else {
55
+
56
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
57
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
58
+ else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
59
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
60
+
61
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
62
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
63
+ else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
64
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
65
+
66
+ }
67
+
68
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
69
+ $.ui.ddmanager.prepareOffsets(this, event);
70
+ }
71
+
72
+ //Regenerate the absolute position used for position checks
73
+ this.positionAbs = this._convertPositionTo("absolute");
74
+
75
+ //Set the helper position
76
+ if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
77
+ if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
78
+
79
+ //Rearrange
80
+ for (var i = this.items.length - 1; i >= 0; i--) {
81
+
82
+ //Cache variables and intersection, continue if no intersection
83
+ var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
84
+ if (!intersection) continue;
85
+
86
+ if(itemElement != this.currentItem[0] //cannot intersect with itself
87
+ && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
88
+ && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
89
+ && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
90
+ //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
91
+ ) {
92
+
93
+ this.direction = intersection == 1 ? "down" : "up";
94
+
95
+ if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
96
+ this._rearrange(event, item);
97
+ } else {
98
+ break;
99
+ }
100
+
101
+ // Clear emtpy ul's/ol's
102
+ this._clearEmpty(itemElement);
103
+
104
+ this._trigger("change", event, this._uiHash());
105
+ break;
106
+ }
107
+ }
108
+
109
+ // Get the real previous item
110
+ itemBefore = this.placeholder[0].previousSibling;
111
+ while (itemBefore != null) {
112
+ if (itemBefore.nodeType == 1 && itemBefore != this.currentItem[0]) {
113
+ break;
114
+ } else {
115
+ itemBefore = itemBefore.previousSibling;
116
+ }
117
+ }
118
+
119
+ parentItem = this.placeholder[0].parentNode.parentNode;
120
+ newList = document.createElement(o.listType);
121
+
122
+ // Make/delete nested ul's/ol's
123
+ if (parentItem != null && parentItem.nodeName == 'LI' && this.positionAbs.left < $(parentItem).offset().left) {
124
+ $(parentItem).after(this.placeholder[0]);
125
+ this._clearEmpty(parentItem);
126
+ } else if (itemBefore != null && itemBefore.nodeName == 'LI' && this.positionAbs.left > $(itemBefore).offset().left + this.options.tabSize) {
127
+ if (!($(itemBefore).hasClass(this.options.disableNesting))) {
128
+ if ($(this.placeholder[0]).hasClass(this.options.errorClass)) {
129
+ $(this.placeholder[0]).css('marginLeft', 0).removeClass(this.options.errorClass);
130
+ }
131
+ if (itemBefore.children[1] == null) {
132
+ itemBefore.appendChild(newList);
133
+ }
134
+ itemBefore.children[1].appendChild(this.placeholder[0]);
135
+ } else {
136
+ $(this.placeholder[0]).addClass(this.options.errorClass).css('marginLeft', this.options.tabSize);
137
+ }
138
+ } else if (itemBefore != null) {
139
+ if ($(this.placeholder[0]).hasClass(this.options.errorClass)) {
140
+ $(this.placeholder[0]).css('marginLeft', 0).removeClass(this.options.errorClass);
141
+ }
142
+ $(itemBefore).after(this.placeholder[0]);
143
+ } else {
144
+ if ($(this.placeholder[0]).hasClass(this.options.errorClass)) {
145
+ $(this.placeholder[0]).css('marginLeft', 0).removeClass(this.options.errorClass);
146
+ }
147
+ }
148
+
149
+ //Post events to containers
150
+ this._contactContainers(event);
151
+
152
+ //Interconnect with droppables
153
+ if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
154
+
155
+ //Call callbacks
156
+ this._trigger('sort', event, this._uiHash());
157
+
158
+ this.lastPositionAbs = this.positionAbs;
159
+ return false;
160
+
161
+ },
162
+
163
+ serialize: function(o) {
164
+
165
+ var items = this._getItemsAsjQuery(o && o.connected);
166
+ var str = []; o = o || {};
167
+
168
+ $(items).each(function() {
169
+ var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
170
+ var pid = ($(o.item || this).parent(o.listType).parent('li').attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
171
+ if(res) str.push((o.key || res[1]+'['+(o.key && o.expression ? res[1] : res[2])+']')+'='+(pid ? (o.key && o.expression ? pid[1] : pid[2]) : 'root'));
172
+ });
173
+
174
+ if(!str.length && o.key) {
175
+ str.push(o.key + '=');
176
+ }
177
+
178
+ return str.join('&');
179
+
180
+ },
181
+
182
+ toArray: function(o) {
183
+
184
+ o = o || {};
185
+ var sDepth = o.startDepthCount || 0;
186
+ var ret = [];
187
+ var left = 2;
188
+
189
+ ret.push({"item_id": 'root', "parent_id": 'none', "depth": sDepth, "left": '1', "right": ($('li', this.element).length + 1) * 2});
190
+
191
+ $(this.element).children('li').each(function() {
192
+ left = _recursiveArray($(this), sDepth + 1, left);
193
+ });
194
+
195
+ return ret;
196
+
197
+ function _recursiveArray(item, depth, left) {
198
+
199
+ right = left + 1;
200
+
201
+ if ($(item).children(o.listType).children('li').length > 0) {
202
+ depth ++;
203
+ $(item).children(o.listType).children('li').each(function() {
204
+ right = _recursiveArray($(this), depth, right);
205
+ });
206
+ depth --;
207
+ }
208
+
209
+ id = $(item).attr('id').match(o.expression || (/(.+)[-=_](.+)/));
210
+
211
+ if (depth === sDepth + 1) pid = 'root';
212
+ else {
213
+ parentItem = $(item).parent(o.listType).parent('li').attr('id').match(o.expression || (/(.+)[-=_](.+)/));
214
+ pid = parentItem[2];
215
+ }
216
+
217
+ ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right});
218
+
219
+ return left = right + 1;
220
+ }
221
+
222
+ },
223
+
224
+ _createPlaceholder: function(that) {
225
+
226
+ var self = that || this, o = self.options;
227
+
228
+ if(!o.placeholder || o.placeholder.constructor == String) {
229
+ var className = o.placeholder;
230
+ o.placeholder = {
231
+ element: function() {
232
+
233
+ var el = $(document.createElement(self.currentItem[0].nodeName))
234
+ .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder")
235
+ .removeClass("ui-sortable-helper")[0];
236
+
237
+ if(!className)
238
+ el.style.visibility = "hidden";
239
+
240
+ return el;
241
+ },
242
+ update: function(container, p) {
243
+
244
+ // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
245
+ // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
246
+ if(className && !o.forcePlaceholderSize) return;
247
+
248
+ //If the element doesn't have an actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
249
+ if(!p.height() || p.css('height') == 'auto') { p.height(self.currentItem.height()); };
250
+ if(!p.width()) { p.width(self.currentItem.width()); };
251
+ }
252
+ };
253
+ }
254
+
255
+ //Create the placeholder
256
+ self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem));
257
+
258
+ //Append it after the actual current item
259
+ self.currentItem.after(self.placeholder);
260
+
261
+ //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
262
+ o.placeholder.update(self, self.placeholder);
263
+
264
+ },
265
+
266
+ _clear: function(event, noPropagation) {
267
+
268
+ $.ui.sortable.prototype._clear.apply(this, arguments);
269
+
270
+ // Clean last empty ul/ol
271
+ for (var i = this.items.length - 1; i >= 0; i--) {
272
+ var item = this.items[i].item[0];
273
+ this._clearEmpty(item);
274
+ }
275
+ return true;
276
+
277
+ },
278
+
279
+ _clearEmpty: function(item) {
280
+
281
+ if (item.children[1] && item.children[1].children.length == 0) {
282
+ item.removeChild(item.children[1]);
283
+ }
284
+
285
+ }
286
+
287
+ }));
288
+
289
+ $.ui.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.ui.nestedSortable.prototype.options);
290
+
291
+ })(jQuery);
@@ -0,0 +1,67 @@
1
+ $(document).ready(function() {
2
+ $.getScript('/javascripts/jquery.hoverIntent.minified.js', function() {
3
+ function linkHover() {
4
+ $(this).next().addClass('link_hover');
5
+ }
6
+
7
+ function linkUnhover() {
8
+ if (!$(this).next().hasClass('pop_up_hover'))
9
+ $(this).next().removeClass('link_hover');
10
+ }
11
+
12
+ function popUpHover() {
13
+ $(this).removeClass('link_hover');
14
+ $(this).addClass('pop_up_hover');
15
+ }
16
+
17
+ function popUpUnhover() {
18
+ $(this).removeClass('pop_up_hover');
19
+ }
20
+
21
+ var linkConfig = {
22
+ interval: 200,
23
+ out: linkUnhover,
24
+ over: linkHover,
25
+ sensitivity: 4,
26
+ timeout: 250
27
+ };
28
+
29
+ var popUpConfig = {
30
+ interval: 0,
31
+ out: popUpUnhover,
32
+ over: popUpHover,
33
+ sensitivity: 4,
34
+ timeout: 250
35
+ };
36
+
37
+ $('.mega_menu').hoverIntent(linkConfig);
38
+ $('.mega_menu_links').hoverIntent(popUpConfig);
39
+ });
40
+
41
+ $.getScript('/javascripts/jquery.ui.nestedSortable.js', function() {
42
+ $('#menu').nestedSortable({
43
+ disableNesting: 'item',
44
+ forcePlaceholderSize: true,
45
+ handle: '.handle',
46
+ items: 'li',
47
+ opacity: .6,
48
+ placeholder: 'placeholder',
49
+ tabSize: 25,
50
+ tolerance: 'pointer',
51
+ toleranceElement: '> div',
52
+ update: function(event, ui) {
53
+ $.ajax({
54
+ type: 'put',
55
+ url: this.getAttribute('data-url'),
56
+ data: { moved: ui.item[0].id, tree: $('#menu').nestedSortable('serialize') }
57
+ });
58
+ }
59
+ });
60
+ });
61
+
62
+ $('#menu .toggle').click(function() {
63
+ $(this).toggleClass('open');
64
+ $(this).toggleClass('closed');
65
+ $(this).parent().next('ol').toggle();
66
+ });
67
+ });
@@ -0,0 +1,82 @@
1
+ .mega_menu {
2
+ background: url(/images/mega_menu.png) no-repeat center;
3
+ cursor: pointer;
4
+ padding-left: 30px;
5
+ }
6
+
7
+ .mega_menu_links {
8
+ background: #ffc;
9
+ border: 1px solid #eea;
10
+ display: none;
11
+ padding: 0.5em;
12
+ position: absolute;
13
+ z-index: 1;
14
+ }
15
+
16
+ .mega_menu_links a:link, a:visited {
17
+ color: blue;
18
+ text-decoration: none;
19
+ }
20
+
21
+ .mega_menu_links a:hover {
22
+ color: green;
23
+ }
24
+
25
+ .link_hover {
26
+ display: block;
27
+ }
28
+
29
+ .pop_up_hover {
30
+ display: block;
31
+ border: 1px solid #cca;
32
+ }
33
+
34
+ .sortable, .sortable ol {
35
+ list-style-type: none;
36
+ margin: 0 0 0 25px;
37
+ padding: 0;
38
+ }
39
+
40
+ .sortable {
41
+ margin: 0;
42
+ }
43
+
44
+ .sortable li {
45
+ margin: 7px 0 0 0;
46
+ padding: 0;
47
+ position: relative;
48
+ }
49
+
50
+ .sortable .handle {
51
+ cursor: move;
52
+ display: inline;
53
+ margin: 0;
54
+ }
55
+
56
+ .placeholder {
57
+ background-color: #cfcfcf;
58
+ }
59
+
60
+ .ui-nestedSortable-error {
61
+ background: #fbe3e4;
62
+ color: #8a1f11;
63
+ }
64
+
65
+ .toggle {
66
+ cursor: pointer;
67
+ padding-right: 1em;
68
+ }
69
+
70
+ #menu span.open {
71
+ background: url(/images/folder_open.png) no-repeat center;
72
+ }
73
+
74
+ #menu span.closed {
75
+ background: url(/images/folder_closed.png) no-repeat center;
76
+ }
77
+
78
+ a.lineage {
79
+ background: url(/images/folder_closed.png) no-repeat left;
80
+ padding-left: 9px;
81
+ padding-right: 5px;
82
+ }