navi 0.1.4 → 0.2.0
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.
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +6 -1
- data/Gemfile.lock +117 -134
- data/README.md +8 -0
- data/features/step_definitions/category_steps.rb +1 -1
- data/features/step_definitions/page_steps.rb +1 -1
- data/features/support/env.rb +7 -2
- data/lib/navi.rb +2 -1
- data/lib/navi/renderers/base.rb +12 -10
- data/lib/navi/renderers/simple_navigation.rb +6 -32
- data/lib/navi/renderers/simple_navigation/dynamic_item.rb +18 -0
- data/lib/navi/renderers/simple_navigation/dynamic_items.rb +26 -0
- data/lib/navi/renderers/simple_navigation/generates_uri.rb +32 -0
- data/lib/navi/renderers/simple_navigation/renderer.rb +27 -0
- data/lib/navi/version.rb +1 -1
- data/navi.gemspec +6 -17
- data/spec/dummy/app/assets/javascripts/application.js +1 -1
- data/spec/dummy/app/controllers/categories_controller.rb +4 -4
- data/spec/dummy/app/controllers/menu_items_controller.rb +11 -4
- data/spec/dummy/app/controllers/pages_controller.rb +5 -4
- data/spec/dummy/app/views/layouts/application.html.erb +1 -1
- data/spec/dummy/config/application.rb +0 -1
- data/spec/dummy/config/navigation.rb +0 -0
- data/spec/dummy/db/seeds.rb +4 -6
- data/spec/dummy/vendor/assets/javascripts/nestedSortable.js +382 -0
- data/spec/navi/navi_spec.rb +3 -3
- data/spec/navi/navigable_spec.rb +2 -2
- data/spec/navi/navigator_spec.rb +7 -7
- data/spec/navi/renderers/simple_navigation/dynamic_item_spec.rb +49 -0
- data/spec/navi/renderers/simple_navigation/dynamic_items_spec.rb +30 -0
- data/spec/navi/renderers/simple_navigation/generates_uri_spec.rb +57 -0
- data/spec/navi/renderers/simple_navigation/renderer_spec.rb +41 -0
- metadata +229 -142
- data/.rvmrc +0 -1
- data/spec/navi/renderers/simple_navigation_spec.rb +0 -49
@@ -1,37 +1,11 @@
|
|
1
1
|
module Navi
|
2
2
|
module Renderers
|
3
|
-
|
4
|
-
|
5
|
-
def render(collection, *args)
|
6
|
-
options = Hash[*args]
|
7
|
-
options[:expand_all] ||= true
|
8
|
-
options[:items] ||= create_dynamic_items(collection)
|
9
|
-
@template.render_navigation options
|
10
|
-
end
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
# Create an array of hashes that can be easily fed into SimpleNavigation
|
15
|
-
# like in the following like:
|
16
|
-
# https://github.com/andi/simple-navigation/wiki/Dynamic-Navigation-Items
|
17
|
-
def create_dynamic_items(collection)
|
18
|
-
nav = []
|
19
|
-
collection.each do |nav_item|
|
20
|
-
item = {}
|
21
|
-
item[:key] = @template.dom_id(nav_item).to_sym
|
22
|
-
item[:name] = nav_item.label
|
23
|
-
if nav_item.url.is_a?(String)
|
24
|
-
item[:url] = nav_item.url
|
25
|
-
else # it's a database record then!
|
26
|
-
item[:url] = @template.polymorphic_path(nav_item.url)
|
27
|
-
end
|
28
|
-
item[:options] = {:title => nav_item.title, :class => nav_item.class.name.underscore}
|
29
|
-
item[:items] = create_dynamic_items(nav_item.children)
|
30
|
-
|
31
|
-
nav << item
|
32
|
-
end
|
33
|
-
nav
|
34
|
-
end
|
3
|
+
module SimpleNavigation
|
35
4
|
end
|
36
5
|
end
|
37
6
|
end
|
7
|
+
|
8
|
+
require 'navi/renderers/simple_navigation/renderer'
|
9
|
+
require 'navi/renderers/simple_navigation/generates_uri'
|
10
|
+
require 'navi/renderers/simple_navigation/dynamic_items'
|
11
|
+
require 'navi/renderers/simple_navigation/dynamic_item'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Navi
|
2
|
+
module Renderers
|
3
|
+
module SimpleNavigation
|
4
|
+
class DynamicItem < Hash
|
5
|
+
|
6
|
+
def initialize(template, nav_item, options={})
|
7
|
+
self[:key] = template.dom_id(nav_item).to_sym
|
8
|
+
self[:name] = nav_item.label
|
9
|
+
self[:url] = GeneratesUri.execute(template, nav_item, options)
|
10
|
+
self[:options] = {title: nav_item.title,
|
11
|
+
class: nav_item.class.name.underscore}
|
12
|
+
self[:items] = DynamicItems.new(template, nav_item.children, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Create an array of hashes that can be easily fed into SimpleNavigation
|
2
|
+
# like in the following like:
|
3
|
+
# https://github.com/andi/simple-navigation/wiki/Dynamic-Navigation-Items
|
4
|
+
module Navi
|
5
|
+
module Renderers
|
6
|
+
module SimpleNavigation
|
7
|
+
class DynamicItems < Array
|
8
|
+
|
9
|
+
def initialize(template, nav_items, options={})
|
10
|
+
@template = template
|
11
|
+
@options = options
|
12
|
+
nav_items.each do |nav_item|
|
13
|
+
self << dynamic_item_for(nav_item)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def dynamic_item_for(nav_item)
|
20
|
+
DynamicItem.new @template, nav_item, @options
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Navi
|
2
|
+
module Renderers
|
3
|
+
module SimpleNavigation
|
4
|
+
class GeneratesUri
|
5
|
+
easy_class_to_instance
|
6
|
+
|
7
|
+
def initialize(template, nav_item, options={})
|
8
|
+
@template = template
|
9
|
+
@nav_item = nav_item
|
10
|
+
@namespace = options[:namespace]
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
url.is_a?(String) ? url : generated_path
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def url
|
20
|
+
@nav_item.url
|
21
|
+
end
|
22
|
+
|
23
|
+
def generated_path
|
24
|
+
args = [@namespace].flatten.compact
|
25
|
+
args << url
|
26
|
+
@template.polymorphic_path(args)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Navi
|
2
|
+
module Renderers
|
3
|
+
module SimpleNavigation
|
4
|
+
class Renderer < Navi::Renderers::Base
|
5
|
+
|
6
|
+
def render(collection, *args)
|
7
|
+
options = Hash[*args]
|
8
|
+
options[:expand_all] ||= true
|
9
|
+
|
10
|
+
@dynamic_items_options = {}
|
11
|
+
@dynamic_items_options[:namespace] = options.delete(:namespace)
|
12
|
+
|
13
|
+
options[:items] ||= create_dynamic_items(collection)
|
14
|
+
|
15
|
+
template.render_navigation options
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def create_dynamic_items(collection)
|
21
|
+
DynamicItems.new(template, collection, @dynamic_items_options)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/navi/version.rb
CHANGED
data/navi.gemspec
CHANGED
@@ -22,31 +22,20 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_runtime_dependency "activesupport", [">= 3.0.0"]
|
23
23
|
s.add_runtime_dependency "activerecord", [">= 3.0.0"]
|
24
24
|
s.add_runtime_dependency "ordered_tree", [">= 0.1.6"]
|
25
|
+
s.add_runtime_dependency 'simple-navigation', ['~> 3.11.0']
|
26
|
+
s.add_runtime_dependency 'easy_class_to_instance_method', '0.0.1'
|
25
27
|
|
26
|
-
s.add_development_dependency "rspec", ["~> 2.6.0"]
|
27
|
-
s.add_development_dependency "bundler", "~> 1.0.0"
|
28
|
-
s.add_development_dependency "simple-navigation", ["3.2.0"]
|
29
|
-
s.add_development_dependency 'inherited_resources', ["~> 1.3.0"]
|
30
|
-
s.add_development_dependency 'guard-rspec'
|
31
|
-
s.add_development_dependency 'libnotify'
|
32
|
-
s.add_development_dependency 'rb-inotify'
|
33
28
|
s.add_development_dependency 'sqlite3'
|
34
|
-
s.add_development_dependency 'apotomo', ['~> 1.2.2']
|
35
29
|
s.add_development_dependency 'rails', ['~> 3.2.0']
|
36
|
-
s.add_development_dependency '
|
37
|
-
s.add_development_dependency '
|
38
|
-
s.add_development_dependency 'jquery-rails', ['~> 2.0.0']
|
39
|
-
s.add_development_dependency 'rspec-rails', ['~> 2.6.1']
|
30
|
+
s.add_development_dependency 'jquery-rails', ['~> 2.2.1']
|
31
|
+
s.add_development_dependency 'rspec-rails', ['~> 2.13.2']
|
40
32
|
s.add_development_dependency 'cucumber-rails', ['0.5.2']
|
41
33
|
s.add_development_dependency 'cucumber'
|
34
|
+
s.add_development_dependency 'selenium-webdriver'
|
42
35
|
s.add_development_dependency 'capybara', [">= 1.0.0.rc1"]
|
43
36
|
s.add_development_dependency 'database_cleaner'
|
44
37
|
s.add_development_dependency 'launchy'
|
45
38
|
s.add_development_dependency 'guard-cucumber', ['0.3.4']
|
46
|
-
s.add_development_dependency 'libnotify'
|
47
|
-
s.add_development_dependency 'rb-inotify'
|
48
39
|
s.add_development_dependency 'nifty-generators'
|
49
|
-
s.add_development_dependency 'factory_girl', '~> 2.
|
50
|
-
s.add_development_dependency 'ruby-debug19'
|
40
|
+
s.add_development_dependency 'factory_girl', '~> 4.2.0'
|
51
41
|
end
|
52
|
-
|
@@ -1,8 +1,8 @@
|
|
1
|
-
class CategoriesController <
|
1
|
+
class CategoriesController < ApplicationController
|
2
|
+
respond_to :html
|
2
3
|
|
3
4
|
def create
|
4
|
-
|
5
|
-
|
6
|
-
end
|
5
|
+
@category = Category.create(params[:category])
|
6
|
+
respond_with @category, location: categories_path
|
7
7
|
end
|
8
8
|
end
|
@@ -1,11 +1,18 @@
|
|
1
|
-
class MenuItemsController <
|
1
|
+
class MenuItemsController < ApplicationController
|
2
2
|
has_widgets do |root|
|
3
3
|
root << widget(:menu_editor)
|
4
4
|
end
|
5
5
|
|
6
|
+
respond_to :html
|
7
|
+
|
8
|
+
def index
|
9
|
+
@menu_items = MenuItem.scoped
|
10
|
+
respond_with @menu_items
|
11
|
+
end
|
12
|
+
|
6
13
|
def update
|
7
|
-
|
8
|
-
|
9
|
-
|
14
|
+
@menu_item = MenuItem.find(params[:id])
|
15
|
+
@menu_item.update_attributes params[:menu_item]
|
16
|
+
respond_with @menu_item, location: menu_items_path
|
10
17
|
end
|
11
18
|
end
|
@@ -1,7 +1,8 @@
|
|
1
|
-
class PagesController <
|
1
|
+
class PagesController < ApplicationController
|
2
|
+
respond_to :html
|
3
|
+
|
2
4
|
def create
|
3
|
-
|
4
|
-
|
5
|
-
end
|
5
|
+
@page = Page.create(params[:page])
|
6
|
+
respond_with @page, location: pages_path
|
6
7
|
end
|
7
8
|
end
|
File without changes
|
data/spec/dummy/db/seeds.rb
CHANGED
@@ -6,10 +6,8 @@
|
|
6
6
|
# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
|
7
7
|
# Mayor.create(:name => 'Daley', :city => cities.first)
|
8
8
|
|
9
|
-
|
9
|
+
FactoryGirl.create :page, :name => "Home"
|
10
|
+
FactoryGirl.create :page, :name => "About"
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
Factory :category, :name => "Cars"
|
15
|
-
Factory :category, :name => "Animals"
|
12
|
+
FactoryGirl.create :category, :name => "Cars"
|
13
|
+
FactoryGirl.create :category, :name => "Animals"
|
@@ -0,0 +1,382 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery UI Nested Sortable
|
3
|
+
* v 1.3.6 / 28 apr 2011
|
4
|
+
* http://mjsarfatti.com/sandbox/nestedSortable
|
5
|
+
*
|
6
|
+
* Depends:
|
7
|
+
* jquery.ui.sortable.js 1.8+
|
8
|
+
*
|
9
|
+
* License CC BY-SA 3.0
|
10
|
+
* Copyright 2010-2011, Manuele J Sarfatti
|
11
|
+
*/
|
12
|
+
|
13
|
+
(function($) {
|
14
|
+
$.widget("ui.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
|
15
|
+
options: {
|
16
|
+
tabSize: 20,
|
17
|
+
disableNesting: 'ui-nestedSortable-no-nesting',
|
18
|
+
errorClass: 'ui-nestedSortable-error',
|
19
|
+
listType: 'ol',
|
20
|
+
maxLevels: 0,
|
21
|
+
revertOnError: 1
|
22
|
+
},//options
|
23
|
+
_create: function() {
|
24
|
+
this.element.data('sortable', this.element.data('nestedSortable'));
|
25
|
+
return $.ui.sortable.prototype._create.apply(this, arguments);
|
26
|
+
},//create
|
27
|
+
destroy: function() {
|
28
|
+
this.element
|
29
|
+
.removeData("nestedSortable")
|
30
|
+
.unbind(".nestedSortable");
|
31
|
+
return $.ui.sortable.prototype.destroy.apply(this, arguments);
|
32
|
+
},//destroy
|
33
|
+
_mouseDrag: function(event) {
|
34
|
+
//Compute the helpers position
|
35
|
+
this.position = this._generatePosition(event);
|
36
|
+
this.positionAbs = this._convertPositionTo("absolute");
|
37
|
+
|
38
|
+
if (!this.lastPositionAbs) {
|
39
|
+
this.lastPositionAbs = this.positionAbs;
|
40
|
+
}
|
41
|
+
|
42
|
+
//Do scrolling
|
43
|
+
if(this.options.scroll) {
|
44
|
+
var o = this.options, scrolled = false;
|
45
|
+
if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
|
46
|
+
|
47
|
+
if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
|
48
|
+
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
|
49
|
+
else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
|
50
|
+
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
|
51
|
+
|
52
|
+
if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
|
53
|
+
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
|
54
|
+
else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
|
55
|
+
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
|
56
|
+
|
57
|
+
} else {
|
58
|
+
|
59
|
+
if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
|
60
|
+
scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
|
61
|
+
else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
|
62
|
+
scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
|
63
|
+
|
64
|
+
if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
|
65
|
+
scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
|
66
|
+
else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
|
67
|
+
scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
|
68
|
+
|
69
|
+
}
|
70
|
+
|
71
|
+
if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
|
72
|
+
$.ui.ddmanager.prepareOffsets(this, event);
|
73
|
+
}
|
74
|
+
|
75
|
+
//Regenerate the absolute position used for position checks
|
76
|
+
this.positionAbs = this._convertPositionTo("absolute");
|
77
|
+
|
78
|
+
//Set the helper position
|
79
|
+
if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
|
80
|
+
if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
|
81
|
+
|
82
|
+
//Rearrange
|
83
|
+
for (var i = this.items.length - 1; i >= 0; i--) {
|
84
|
+
|
85
|
+
//Cache variables and intersection, continue if no intersection
|
86
|
+
var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
|
87
|
+
if (!intersection) continue;
|
88
|
+
|
89
|
+
if(itemElement != this.currentItem[0] //cannot intersect with itself
|
90
|
+
&& this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
|
91
|
+
&& !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
|
92
|
+
&& (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
|
93
|
+
//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
|
94
|
+
) {
|
95
|
+
|
96
|
+
$(itemElement).mouseenter();
|
97
|
+
|
98
|
+
this.direction = intersection == 1 ? "down" : "up";
|
99
|
+
|
100
|
+
if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
|
101
|
+
$(itemElement).mouseleave();
|
102
|
+
this._rearrange(event, item);
|
103
|
+
} else {
|
104
|
+
break;
|
105
|
+
}
|
106
|
+
|
107
|
+
// Clear emtpy ul's/ol's
|
108
|
+
this._clearEmpty(itemElement);
|
109
|
+
|
110
|
+
this._trigger("change", event, this._uiHash());
|
111
|
+
break;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
var parentItem = (this.placeholder[0].parentNode.parentNode
|
116
|
+
&& $(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
|
117
|
+
? $(this.placeholder[0].parentNode.parentNode)
|
118
|
+
: null,
|
119
|
+
level = this._getLevel(this.placeholder),
|
120
|
+
childLevels = this._getChildLevels(this.helper),
|
121
|
+
previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
|
122
|
+
|
123
|
+
if (previousItem != null) {
|
124
|
+
while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0]) {
|
125
|
+
if (previousItem[0].previousSibling) {
|
126
|
+
previousItem = $(previousItem[0].previousSibling);
|
127
|
+
} else {
|
128
|
+
previousItem = null;
|
129
|
+
break;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
newList = document.createElement(o.listType);
|
135
|
+
|
136
|
+
this.beyondMaxLevels = 0;
|
137
|
+
|
138
|
+
// If the item is moved to the left, send it to its parent level
|
139
|
+
if (parentItem != null && this.positionAbs.left < parentItem.offset().left) {
|
140
|
+
parentItem.after(this.placeholder[0]);
|
141
|
+
this._clearEmpty(parentItem[0]);
|
142
|
+
this._trigger("change", event, this._uiHash());
|
143
|
+
}
|
144
|
+
// If the item is below another one and is moved to the right, make it a children of it
|
145
|
+
else if (previousItem != null && this.positionAbs.left > previousItem.offset().left + o.tabSize) {
|
146
|
+
this._isAllowed(previousItem, level+childLevels+1);
|
147
|
+
if (!previousItem.children(o.listType).length) {
|
148
|
+
previousItem[0].appendChild(newList);
|
149
|
+
}
|
150
|
+
previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
|
151
|
+
this._trigger("change", event, this._uiHash());
|
152
|
+
}
|
153
|
+
else {
|
154
|
+
this._isAllowed(parentItem, level+childLevels);
|
155
|
+
}
|
156
|
+
|
157
|
+
//Post events to containers
|
158
|
+
this._contactContainers(event);
|
159
|
+
|
160
|
+
//Interconnect with droppables
|
161
|
+
if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
|
162
|
+
|
163
|
+
//Call callbacks
|
164
|
+
this._trigger('sort', event, this._uiHash());
|
165
|
+
|
166
|
+
this.lastPositionAbs = this.positionAbs;
|
167
|
+
return false;
|
168
|
+
},//_mouseDrag
|
169
|
+
_mouseStop: function(event, noPropagation) {
|
170
|
+
// If the item is in a position not allowed, send it back
|
171
|
+
if (this.beyondMaxLevels) {
|
172
|
+
|
173
|
+
this.placeholder.removeClass(this.options.errorClass);
|
174
|
+
|
175
|
+
if (this.options.revertOnError) {
|
176
|
+
if (this.domPosition.prev) {
|
177
|
+
$(this.domPosition.prev).after(this.placeholder);
|
178
|
+
} else {
|
179
|
+
$(this.domPosition.parent).prepend(this.placeholder);
|
180
|
+
}
|
181
|
+
this._trigger("revert", event, this._uiHash());
|
182
|
+
} else {
|
183
|
+
var parent = this.placeholder.parent().closest(this.options.items);
|
184
|
+
|
185
|
+
for (var i = this.beyondMaxLevels - 1; i > 0; i--) {
|
186
|
+
parent = parent.parent().closest(this.options.items);
|
187
|
+
}
|
188
|
+
|
189
|
+
parent.after(this.placeholder);
|
190
|
+
this._trigger("change", event, this._uiHash());
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
// Clean last empty ul/ol
|
195
|
+
for (var i = this.items.length - 1; i >= 0; i--) {
|
196
|
+
var item = this.items[i].item[0];
|
197
|
+
this._clearEmpty(item);
|
198
|
+
}
|
199
|
+
|
200
|
+
$.ui.sortable.prototype._mouseStop.apply(this, arguments);
|
201
|
+
},//_mouseStop
|
202
|
+
serialize: function(o) {
|
203
|
+
// 'o' is a hash of the options of the plugin (?)
|
204
|
+
|
205
|
+
// items is an array the dom elements lifted from the page, so we can work on them.
|
206
|
+
// It looks something like [li#menu_item_37.menu_item, li#menu_item_38.menu_item, ...]
|
207
|
+
var items = this._getItemsAsjQuery(o && o.connected),
|
208
|
+
str = []; o = o || {};
|
209
|
+
|
210
|
+
// Now we go through each of these items
|
211
|
+
$(items).each(function() {
|
212
|
+
var res = ($(o.item || this).attr(o.attribute || 'id') || '')
|
213
|
+
.match(
|
214
|
+
o.expression || (/(.+)[-=_](.+)/)),
|
215
|
+
pid = ($(o.item || this).parent(o.listType)
|
216
|
+
.parent('li')
|
217
|
+
.attr(o.attribute || 'id') || '')
|
218
|
+
.match(o.expression || (/(.+)[-=_](.+)/));
|
219
|
+
|
220
|
+
// At this point...
|
221
|
+
// 'res' looks like this: ["menu_item_47", "menu_item", "47"]
|
222
|
+
// pid looks like this, IF the item (res) has a parent: ["menu_item_46", "menu_item", "46"]
|
223
|
+
|
224
|
+
// Here we setup the response's parent_id
|
225
|
+
if (res) {
|
226
|
+
// Updated the following line to have res[0] (instead of res[2]), which will make the itemName be menu_item_47
|
227
|
+
itemName = (o.key && o.expression ? res[1] : res[0]);
|
228
|
+
|
229
|
+
// itemScope looks like this: menu_item[menu_item_37]
|
230
|
+
itemScope = o.key || res[1] + '[' + itemName + ']'
|
231
|
+
|
232
|
+
//create the parentId string, which will look like menu_item[menu_item_37][parent_id]=root
|
233
|
+
parentStr = itemScope + '[parent_id]=' + (pid ? (o.key && o.expression ? pid[1] : pid[2]) : 'root')
|
234
|
+
|
235
|
+
//create the position string, which will look like menu_item[menu_item_37][position]=0
|
236
|
+
//this is 0-based position
|
237
|
+
positionStr = itemScope + '[position]=' + $(this).index();
|
238
|
+
|
239
|
+
//push the parentStr and positionStr strings into the str array
|
240
|
+
str.push(parentStr);
|
241
|
+
str.push(positionStr);
|
242
|
+
}
|
243
|
+
});
|
244
|
+
|
245
|
+
if(!str.length && o.key) {
|
246
|
+
str.push(o.key + '=');
|
247
|
+
}
|
248
|
+
|
249
|
+
return str.join('&');
|
250
|
+
},//serialize
|
251
|
+
toHierarchy: function(o) {
|
252
|
+
o = o || {};
|
253
|
+
var sDepth = o.startDepthCount || 0,
|
254
|
+
ret = [];
|
255
|
+
|
256
|
+
$(this.element).children('li').each(function () {
|
257
|
+
var level = _recursiveItems($(this));
|
258
|
+
ret.push(level);
|
259
|
+
});
|
260
|
+
|
261
|
+
return ret;
|
262
|
+
|
263
|
+
function _recursiveItems(li) {
|
264
|
+
var id = ($(li).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
|
265
|
+
if (id) {
|
266
|
+
var item = {"id" : id[2]};
|
267
|
+
if ($(li).children(o.listType).children('li').length > 0) {
|
268
|
+
item.children = [];
|
269
|
+
$(li).children(o.listType).children('li').each(function() {
|
270
|
+
var level = _recursiveItems($(this));
|
271
|
+
item.children.push(level);
|
272
|
+
});
|
273
|
+
}
|
274
|
+
return item;
|
275
|
+
}
|
276
|
+
}
|
277
|
+
},//toHierarchy
|
278
|
+
toArray: function(o) {
|
279
|
+
o = o || {};
|
280
|
+
var sDepth = o.startDepthCount || 0,
|
281
|
+
ret = [],
|
282
|
+
left = 2;
|
283
|
+
|
284
|
+
ret.push({
|
285
|
+
"item_id": 'root',
|
286
|
+
"parent_id": 'none',
|
287
|
+
"depth": sDepth,
|
288
|
+
"left": '1',
|
289
|
+
"right": ($('li', this.element).length + 1) * 2
|
290
|
+
});
|
291
|
+
|
292
|
+
$(this.element).children('li').each(function () {
|
293
|
+
left = _recursiveArray(this, sDepth + 1, left);
|
294
|
+
});
|
295
|
+
|
296
|
+
ret = ret.sort(function(a,b){ return (a.left - b.left); });
|
297
|
+
|
298
|
+
return ret;
|
299
|
+
|
300
|
+
function _recursiveArray(item, depth, left) {
|
301
|
+
var right = left + 1,
|
302
|
+
id,
|
303
|
+
pid;
|
304
|
+
|
305
|
+
if ($(item).children(o.listType).children('li').length > 0) {
|
306
|
+
depth ++;
|
307
|
+
$(item).children(o.listType).children('li').each(function () {
|
308
|
+
right = _recursiveArray($(this), depth, right);
|
309
|
+
});
|
310
|
+
depth --;
|
311
|
+
}
|
312
|
+
|
313
|
+
id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
|
314
|
+
|
315
|
+
if (depth === sDepth + 1) {
|
316
|
+
pid = 'root';
|
317
|
+
} else {
|
318
|
+
var parentItem = ($(item).parent(o.listType)
|
319
|
+
.parent('li')
|
320
|
+
.attr(o.attribute || 'id'))
|
321
|
+
.match(o.expression || (/(.+)[-=_](.+)/));
|
322
|
+
pid = parentItem[2];
|
323
|
+
}
|
324
|
+
if (id) {
|
325
|
+
ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right});
|
326
|
+
}
|
327
|
+
left = right + 1;
|
328
|
+
return left;
|
329
|
+
} //_recursiveArray
|
330
|
+
},//toArray
|
331
|
+
_clearEmpty: function(item) {
|
332
|
+
var emptyList = $(item).children(this.options.listType);
|
333
|
+
if (emptyList.length && !emptyList.children().length) {
|
334
|
+
emptyList.remove();
|
335
|
+
}
|
336
|
+
},//_clearEmpty
|
337
|
+
_getLevel: function(item) {
|
338
|
+
var level = 1;
|
339
|
+
if (this.options.listType) {
|
340
|
+
var list = item.closest(this.options.listType);
|
341
|
+
while (!list.is('.ui-sortable')) {
|
342
|
+
level++;
|
343
|
+
list = list.parent().closest(this.options.listType);
|
344
|
+
}
|
345
|
+
}
|
346
|
+
return level;
|
347
|
+
}, //_getLevel
|
348
|
+
_getChildLevels: function(parent, depth) {
|
349
|
+
var self = this,
|
350
|
+
o = this.options,
|
351
|
+
result = 0;
|
352
|
+
depth = depth || 0;
|
353
|
+
|
354
|
+
$(parent).children(o.listType).children(o.items).each(function (index, child) {
|
355
|
+
result = Math.max(self._getChildLevels(child, depth + 1), result);
|
356
|
+
});
|
357
|
+
|
358
|
+
return depth ? result + 1 : result;
|
359
|
+
}, //_getChildLevels
|
360
|
+
_isAllowed: function(parentItem, levels) {
|
361
|
+
var o = this.options;
|
362
|
+
// Are we trying to nest under a no-nest or are we nesting too deep?
|
363
|
+
if (parentItem == null || !(parentItem.hasClass(o.disableNesting))) {
|
364
|
+
if (o.maxLevels < levels && o.maxLevels != 0) {
|
365
|
+
this.placeholder.addClass(o.errorClass);
|
366
|
+
this.beyondMaxLevels = levels - o.maxLevels;
|
367
|
+
} else {
|
368
|
+
this.placeholder.removeClass(o.errorClass);
|
369
|
+
this.beyondMaxLevels = 0;
|
370
|
+
}
|
371
|
+
} else {
|
372
|
+
this.placeholder.addClass(o.errorClass);
|
373
|
+
if (o.maxLevels < levels && o.maxLevels != 0) {
|
374
|
+
this.beyondMaxLevels = levels - o.maxLevels;
|
375
|
+
} else {
|
376
|
+
this.beyondMaxLevels = 1;
|
377
|
+
}
|
378
|
+
}
|
379
|
+
} //_isAllowed
|
380
|
+
}));//widget
|
381
|
+
$.ui.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.ui.nestedSortable.prototype.options);
|
382
|
+
})(jQuery);
|