navi 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +1 -0
  4. data/Gemfile +41 -0
  5. data/Gemfile.lock +196 -0
  6. data/Guardfile +23 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.textile +26 -0
  9. data/Rakefile +50 -0
  10. data/VERSION +1 -0
  11. data/features/create_menu_items.feature +13 -0
  12. data/features/step_definitions/category_steps.rb +3 -0
  13. data/features/step_definitions/menu_item_steps.rb +19 -0
  14. data/features/step_definitions/page_steps.rb +3 -0
  15. data/features/step_definitions/web_steps.rb +211 -0
  16. data/features/support/env.rb +61 -0
  17. data/features/support/paths.rb +33 -0
  18. data/features/support/selectors.rb +39 -0
  19. data/lib/navi/helpers.rb +24 -0
  20. data/lib/navi/navigable/base.rb +16 -0
  21. data/lib/navi/navigable/instance_methods.rb +24 -0
  22. data/lib/navi/navigator/.base.rb.swo +0 -0
  23. data/lib/navi/navigator/base.rb +11 -0
  24. data/lib/navi/navigator/class_methods.rb +27 -0
  25. data/lib/navi/navigator/instance_methods.rb +57 -0
  26. data/lib/navi/railtie.rb +11 -0
  27. data/lib/navi/renderers/base.rb +31 -0
  28. data/lib/navi/renderers/simple_navigation.rb +30 -0
  29. data/lib/navi.rb +29 -0
  30. data/navi.gemspec +281 -0
  31. data/spec/blueprints.rb +16 -0
  32. data/spec/dummy/.gitignore +6 -0
  33. data/spec/dummy/Rakefile +7 -0
  34. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  35. data/spec/dummy/app/controllers/categories_controller.rb +7 -0
  36. data/spec/dummy/app/controllers/menu_items_controller.rb +15 -0
  37. data/spec/dummy/app/controllers/pages_controller.rb +7 -0
  38. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  39. data/spec/dummy/app/models/category.rb +3 -0
  40. data/spec/dummy/app/models/menu_item.rb +2 -0
  41. data/spec/dummy/app/models/page.rb +3 -0
  42. data/spec/dummy/app/views/categories/_form.html.haml +2 -0
  43. data/spec/dummy/app/views/categories/edit.html.haml +5 -0
  44. data/spec/dummy/app/views/categories/index.html.haml +17 -0
  45. data/spec/dummy/app/views/categories/new.html.haml +5 -0
  46. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  47. data/spec/dummy/app/views/menu_items/edit.html.haml +14 -0
  48. data/spec/dummy/app/views/menu_items/index.html.haml +11 -0
  49. data/spec/dummy/app/views/pages/_form.html.haml +2 -0
  50. data/spec/dummy/app/views/pages/edit.html.haml +5 -0
  51. data/spec/dummy/app/views/pages/index.html.haml +17 -0
  52. data/spec/dummy/app/views/pages/new.html.haml +5 -0
  53. data/spec/dummy/app/widgets/menu_editor/category/form/.display.html.haml.swo +0 -0
  54. data/spec/dummy/app/widgets/menu_editor/category/form/display.html.haml +7 -0
  55. data/spec/dummy/app/widgets/menu_editor/category/form_widget.rb +18 -0
  56. data/spec/dummy/app/widgets/menu_editor/display.html.haml +5 -0
  57. data/spec/dummy/app/widgets/menu_editor/page/form/.display.html.haml.swo +0 -0
  58. data/spec/dummy/app/widgets/menu_editor/page/form/display.html.haml +8 -0
  59. data/spec/dummy/app/widgets/menu_editor/page/form_widget.rb +18 -0
  60. data/spec/dummy/app/widgets/menu_editor/tree/display.html.haml +4 -0
  61. data/spec/dummy/app/widgets/menu_editor/tree/item.html.haml +7 -0
  62. data/spec/dummy/app/widgets/menu_editor/tree/items.html.haml +2 -0
  63. data/spec/dummy/app/widgets/menu_editor/tree_widget.rb +48 -0
  64. data/spec/dummy/app/widgets/menu_editor_widget.rb +11 -0
  65. data/spec/dummy/config/application.rb +45 -0
  66. data/spec/dummy/config/boot.rb +10 -0
  67. data/spec/dummy/config/cucumber.yml +8 -0
  68. data/spec/dummy/config/database.yml +19 -0
  69. data/spec/dummy/config/environment.rb +5 -0
  70. data/spec/dummy/config/environments/development.rb +26 -0
  71. data/spec/dummy/config/environments/production.rb +49 -0
  72. data/spec/dummy/config/environments/test.rb +35 -0
  73. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  74. data/spec/dummy/config/initializers/inflections.rb +10 -0
  75. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  76. data/spec/dummy/config/initializers/navigable.rb +1 -0
  77. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  78. data/spec/dummy/config/initializers/session_store.rb +8 -0
  79. data/spec/dummy/config/locales/en.yml +5 -0
  80. data/spec/dummy/config/navigation.rb +7 -0
  81. data/spec/dummy/config/routes.rb +61 -0
  82. data/spec/dummy/config.ru +4 -0
  83. data/spec/dummy/db/migrate/20110607155019_create_menu_items.rb +20 -0
  84. data/spec/dummy/db/migrate/20110607155202_create_categories.rb +13 -0
  85. data/spec/dummy/db/migrate/20110607160052_create_pages.rb +13 -0
  86. data/spec/dummy/db/schema.rb +41 -0
  87. data/spec/dummy/db/seeds.rb +15 -0
  88. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  89. data/spec/dummy/lib/tasks/cucumber.rake +57 -0
  90. data/spec/dummy/public/404.html +26 -0
  91. data/spec/dummy/public/422.html +26 -0
  92. data/spec/dummy/public/500.html +26 -0
  93. data/spec/dummy/public/favicon.ico +0 -0
  94. data/spec/dummy/public/images/rails.png +0 -0
  95. data/spec/dummy/public/index.html +239 -0
  96. data/spec/dummy/public/javascripts/application.js +2 -0
  97. data/spec/dummy/public/javascripts/jquery-ui.js +11603 -0
  98. data/spec/dummy/public/javascripts/jquery-ui.min.js +406 -0
  99. data/spec/dummy/public/javascripts/jquery.js +8936 -0
  100. data/spec/dummy/public/javascripts/jquery.min.js +18 -0
  101. data/spec/dummy/public/javascripts/jquery_ujs.js +315 -0
  102. data/spec/dummy/public/javascripts/menu_items/index.js +40 -0
  103. data/spec/dummy/public/javascripts/rails.js +315 -0
  104. data/spec/dummy/public/robots.txt +5 -0
  105. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  106. data/spec/dummy/script/cucumber +10 -0
  107. data/spec/dummy/script/rails +6 -0
  108. data/spec/dummy/vendor/plugins/.gitkeep +0 -0
  109. data/spec/navi/helpers_spec.rb +5 -0
  110. data/spec/navi/navi_spec.rb +76 -0
  111. data/spec/navi/navigator_spec.rb +204 -0
  112. data/spec/navi/renderers/simple_navigation_spec.rb +49 -0
  113. data/spec/spec_helper.rb +125 -0
  114. metadata +683 -0
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Unobtrusive scripting adapter for jQuery
3
+ *
4
+ * Requires jQuery 1.4.4 or later.
5
+ * https://github.com/rails/jquery-ujs
6
+
7
+ * Uploading file using rails.js
8
+ * =============================
9
+ *
10
+ * By default, browsers do not allow files to be uploaded via AJAX. As a result, if there are any non-blank file fields
11
+ * in the remote form, this adapter aborts the AJAX submission and allows the form to submit through standard means.
12
+ *
13
+ * The `ajax:aborted:file` event allows you to bind your own handler to process the form submission however you wish.
14
+ *
15
+ * Ex:
16
+ * $('form').live('ajax:aborted:file', function(event, elements){
17
+ * // Implement own remote file-transfer handler here for non-blank file inputs passed in `elements`.
18
+ * // Returning false in this handler tells rails.js to disallow standard form submission
19
+ * return false;
20
+ * });
21
+ *
22
+ * The `ajax:aborted:file` event is fired when a file-type input is detected with a non-blank value.
23
+ *
24
+ * Third-party tools can use this hook to detect when an AJAX file upload is attempted, and then use
25
+ * techniques like the iframe method to upload the file instead.
26
+ *
27
+ * Required fields in rails.js
28
+ * ===========================
29
+ *
30
+ * If any blank required inputs (required="required") are detected in the remote form, the whole form submission
31
+ * is canceled. Note that this is unlike file inputs, which still allow standard (non-AJAX) form submission.
32
+ *
33
+ * The `ajax:aborted:required` event allows you to bind your own handler to inform the user of blank required inputs.
34
+ *
35
+ * !! Note that Opera does not fire the form's submit event if there are blank required inputs, so this event may never
36
+ * get fired in Opera. This event is what causes other browsers to exhibit the same submit-aborting behavior.
37
+ *
38
+ * Ex:
39
+ * $('form').live('ajax:aborted:required', function(event, elements){
40
+ * // Returning false in this handler tells rails.js to submit the form anyway.
41
+ * // The blank required inputs are passed to this function in `elements`.
42
+ * return ! confirm("Would you like to submit the form with missing info?");
43
+ * });
44
+ */
45
+
46
+ (function($) {
47
+ // Shorthand to make it a little easier to call public rails functions from within rails.js
48
+ var rails;
49
+
50
+ $.rails = rails = {
51
+ // Link elements bound by jquery-ujs
52
+ linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]',
53
+
54
+ // Form elements bound by jquery-ujs
55
+ formSubmitSelector: 'form',
56
+
57
+ // Form input elements bound by jquery-ujs
58
+ formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])',
59
+
60
+ // Form input elements disabled during form submission
61
+ disableSelector: 'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]',
62
+
63
+ // Form input elements re-enabled after form submission
64
+ enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled',
65
+
66
+ // Form required input elements
67
+ requiredInputSelector: 'input[name][required]:not([disabled]),textarea[name][required]:not([disabled])',
68
+
69
+ // Form file input elements
70
+ fileInputSelector: 'input:file',
71
+
72
+ // Make sure that every Ajax request sends the CSRF token
73
+ CSRFProtection: function(xhr) {
74
+ var token = $('meta[name="csrf-token"]').attr('content');
75
+ if (token) xhr.setRequestHeader('X-CSRF-Token', token);
76
+ },
77
+
78
+ // Triggers an event on an element and returns false if the event result is false
79
+ fire: function(obj, name, data) {
80
+ var event = $.Event(name);
81
+ obj.trigger(event, data);
82
+ return event.result !== false;
83
+ },
84
+
85
+ // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
86
+ confirm: function(message) {
87
+ return confirm(message);
88
+ },
89
+
90
+ // Default ajax function, may be overridden with custom function in $.rails.ajax
91
+ ajax: function(options) {
92
+ return $.ajax(options);
93
+ },
94
+
95
+ // Submits "remote" forms and links with ajax
96
+ handleRemote: function(element) {
97
+ var method, url, data,
98
+ dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
99
+
100
+ if (rails.fire(element, 'ajax:before')) {
101
+
102
+ if (element.is('form')) {
103
+ method = element.attr('method');
104
+ url = element.attr('action');
105
+ data = element.serializeArray();
106
+ // memoized value from clicked submit button
107
+ var button = element.data('ujs:submit-button');
108
+ if (button) {
109
+ data.push(button);
110
+ element.data('ujs:submit-button', null);
111
+ }
112
+ } else {
113
+ method = element.data('method');
114
+ url = element.attr('href');
115
+ data = element.data('params') || null;
116
+ }
117
+
118
+ rails.ajax({
119
+ url: url, type: method || 'GET', data: data, dataType: dataType,
120
+ // stopping the "ajax:beforeSend" event will cancel the ajax request
121
+ beforeSend: function(xhr, settings) {
122
+ if (settings.dataType === undefined) {
123
+ xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
124
+ }
125
+ return rails.fire(element, 'ajax:beforeSend', [xhr, settings]);
126
+ },
127
+ success: function(data, status, xhr) {
128
+ element.trigger('ajax:success', [data, status, xhr]);
129
+ },
130
+ complete: function(xhr, status) {
131
+ element.trigger('ajax:complete', [xhr, status]);
132
+ },
133
+ error: function(xhr, status, error) {
134
+ element.trigger('ajax:error', [xhr, status, error]);
135
+ }
136
+ });
137
+ }
138
+ },
139
+
140
+ // Handles "data-method" on links such as:
141
+ // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
142
+ handleMethod: function(link) {
143
+ var href = link.attr('href'),
144
+ method = link.data('method'),
145
+ csrf_token = $('meta[name=csrf-token]').attr('content'),
146
+ csrf_param = $('meta[name=csrf-param]').attr('content'),
147
+ form = $('<form method="post" action="' + href + '"></form>'),
148
+ metadata_input = '<input name="_method" value="' + method + '" type="hidden" />';
149
+
150
+ if (csrf_param !== undefined && csrf_token !== undefined) {
151
+ metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
152
+ }
153
+
154
+ form.hide().append(metadata_input).appendTo('body');
155
+ form.submit();
156
+ },
157
+
158
+ /* Disables form elements:
159
+ - Caches element value in 'ujs:enable-with' data store
160
+ - Replaces element text with value of 'data-disable-with' attribute
161
+ - Adds disabled=disabled attribute
162
+ */
163
+ disableFormElements: function(form) {
164
+ form.find(rails.disableSelector).each(function() {
165
+ var element = $(this), method = element.is('button') ? 'html' : 'val';
166
+ element.data('ujs:enable-with', element[method]());
167
+ element[method](element.data('disable-with'));
168
+ element.attr('disabled', 'disabled');
169
+ });
170
+ },
171
+
172
+ /* Re-enables disabled form elements:
173
+ - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
174
+ - Removes disabled attribute
175
+ */
176
+ enableFormElements: function(form) {
177
+ form.find(rails.enableSelector).each(function() {
178
+ var element = $(this), method = element.is('button') ? 'html' : 'val';
179
+ if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
180
+ element.removeAttr('disabled');
181
+ });
182
+ },
183
+
184
+ /* For 'data-confirm' attribute:
185
+ - Fires `confirm` event
186
+ - Shows the confirmation dialog
187
+ - Fires the `confirm:complete` event
188
+
189
+ Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
190
+ Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
191
+ Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
192
+ return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
193
+ */
194
+ allowAction: function(element) {
195
+ var message = element.data('confirm'),
196
+ answer = false, callback;
197
+ if (!message) { return true; }
198
+
199
+ if (rails.fire(element, 'confirm')) {
200
+ answer = rails.confirm(message);
201
+ callback = rails.fire(element, 'confirm:complete', [answer]);
202
+ }
203
+ return answer && callback;
204
+ },
205
+
206
+ // Helper function which checks for blank inputs in a form that match the specified CSS selector
207
+ blankInputs: function(form, specifiedSelector, nonBlank) {
208
+ var inputs = $(), input,
209
+ selector = specifiedSelector || 'input,textarea';
210
+ form.find(selector).each(function() {
211
+ input = $(this);
212
+ // Collect non-blank inputs if nonBlank option is true, otherwise, collect blank inputs
213
+ if (nonBlank ? input.val() : !input.val()) {
214
+ inputs = inputs.add(input);
215
+ }
216
+ });
217
+ return inputs.length ? inputs : false;
218
+ },
219
+
220
+ // Helper function which checks for non-blank inputs in a form that match the specified CSS selector
221
+ nonBlankInputs: function(form, specifiedSelector) {
222
+ return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
223
+ },
224
+
225
+ // Helper function, needed to provide consistent behavior in IE
226
+ stopEverything: function(e) {
227
+ $(e.target).trigger('ujs:everythingStopped');
228
+ e.stopImmediatePropagation();
229
+ return false;
230
+ },
231
+
232
+ // find all the submit events directly bound to the form and
233
+ // manually invoke them. If anyone returns false then stop the loop
234
+ callFormSubmitBindings: function(form) {
235
+ var events = form.data('events'), continuePropagation = true;
236
+ if (events !== undefined && events['submit'] !== undefined) {
237
+ $.each(events['submit'], function(i, obj){
238
+ if (typeof obj.handler === 'function') return continuePropagation = obj.handler(obj.data);
239
+ });
240
+ }
241
+ return continuePropagation;
242
+ }
243
+ };
244
+
245
+ // ajaxPrefilter is a jQuery 1.5 feature
246
+ if ('ajaxPrefilter' in $) {
247
+ $.ajaxPrefilter(function(options, originalOptions, xhr){ rails.CSRFProtection(xhr); });
248
+ } else {
249
+ $(document).ajaxSend(function(e, xhr){ rails.CSRFProtection(xhr); });
250
+ }
251
+
252
+ $(rails.linkClickSelector).live('click.rails', function(e) {
253
+ var link = $(this);
254
+ if (!rails.allowAction(link)) return rails.stopEverything(e);
255
+
256
+ if (link.data('remote') !== undefined) {
257
+ rails.handleRemote(link);
258
+ return false;
259
+ } else if (link.data('method')) {
260
+ rails.handleMethod(link);
261
+ return false;
262
+ }
263
+ });
264
+
265
+ $(rails.formSubmitSelector).live('submit.rails', function(e) {
266
+ var form = $(this),
267
+ remote = form.data('remote') !== undefined,
268
+ blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector),
269
+ nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
270
+
271
+ if (!rails.allowAction(form)) return rails.stopEverything(e);
272
+
273
+ // skip other logic when required values are missing or file upload is present
274
+ if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
275
+ return rails.stopEverything(e);
276
+ }
277
+
278
+ if (remote) {
279
+ if (nonBlankFileInputs) {
280
+ return rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
281
+ }
282
+
283
+ // If browser does not support submit bubbling, then this live-binding will be called before direct
284
+ // bindings. Therefore, we should directly call any direct bindings before remotely submitting form.
285
+ if (!$.support.submitBubbles && rails.callFormSubmitBindings(form) === false) return rails.stopEverything(e);
286
+
287
+ rails.handleRemote(form);
288
+ return false;
289
+ } else {
290
+ // slight timeout so that the submit button gets properly serialized
291
+ setTimeout(function(){ rails.disableFormElements(form); }, 13);
292
+ }
293
+ });
294
+
295
+ $(rails.formInputClickSelector).live('click.rails', function(event) {
296
+ var button = $(this);
297
+
298
+ if (!rails.allowAction(button)) return rails.stopEverything(event);
299
+
300
+ // register the pressed submit button
301
+ var name = button.attr('name'),
302
+ data = name ? {name:name, value:button.val()} : null;
303
+
304
+ button.closest('form').data('ujs:submit-button', data);
305
+ });
306
+
307
+ $(rails.formSubmitSelector).live('ajax:beforeSend.rails', function(event) {
308
+ if (this == event.target) rails.disableFormElements($(this));
309
+ });
310
+
311
+ $(rails.formSubmitSelector).live('ajax:complete.rails', function(event) {
312
+ if (this == event.target) rails.enableFormElements($(this));
313
+ });
314
+
315
+ })( jQuery );
@@ -0,0 +1,5 @@
1
+ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-Agent: *
5
+ # Disallow: /
File without changes
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
4
+ if vendored_cucumber_bin
5
+ load File.expand_path(vendored_cucumber_bin)
6
+ else
7
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
8
+ require 'cucumber'
9
+ load Cucumber::BINARY
10
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
File without changes
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Navi::Helpers do
4
+
5
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe Navi do
4
+ before :all do
5
+ # Since our test app uses :menu_item instead of the default :nav_item,
6
+ # Set it here
7
+ Navi.navigator = :menu_item
8
+ end
9
+
10
+ describe "with renderers," do
11
+ before do
12
+ class SomeRenderer
13
+ end
14
+ end
15
+
16
+ it "should default to Navi::Renderers::SimpleNavigation" do
17
+ Navi.renderer.should == Navi::Renderers::SimpleNavigation
18
+ end
19
+
20
+ it "should allow customization" do
21
+ Navi.renderer = SomeRenderer
22
+ Navi.renderer.should == SomeRenderer
23
+ end
24
+ end
25
+
26
+ describe "#to_navigator" do
27
+ describe "when the nav_item exists" do
28
+ it "should return the nav_item" do
29
+ c = Category.create
30
+ nav_item = MenuItem.create :navigable => c
31
+ c.to_navigator.should == nav_item
32
+ end
33
+ end
34
+
35
+ describe "when the nav_item does not exist" do
36
+ it "should return a new nav_item" do
37
+ c = Category.create
38
+ nav_item = c.to_navigator
39
+ nav_item.should be_new_record
40
+ nav_item.navigable.should == c
41
+ end
42
+ end
43
+
44
+ describe "and :label is passed" do
45
+ it "should create a new nav_item with the passed label" do
46
+ Category.create.to_navigator(:label => "Bosch").label.should == "Bosch"
47
+ end
48
+ end
49
+
50
+ describe "and :title is passed" do
51
+ it "should create a new nav_item with the passed title" do
52
+ Category.create.to_navigator(:title => "Titulo").title.should == "Titulo"
53
+ end
54
+ end
55
+
56
+ describe "when a parent is specified" do
57
+ it "should be created under that parent" do
58
+ cars = Category.create :name => "Cars"
59
+ chevy = Category.create :name => "Chevy"
60
+ cars_nav = cars.to_navigator
61
+ cars_nav.save
62
+ chevy_nav = chevy.to_navigator(:parent_id => cars_nav.id)
63
+ chevy_nav.save
64
+ chevy_nav.parent.should == cars_nav
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "#to_navigator!" do
70
+ it "should immediately create the navigator item" do
71
+ category = Category.make
72
+ navigator = category.to_navigator!
73
+ navigator.should_not be_new_record
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,204 @@
1
+ require 'spec_helper'
2
+
3
+ describe MenuItem do
4
+ #before {reset_database}
5
+ describe "when configuring ordered_tree" do
6
+ # After we run the tests, reset the ordered tree changes we may have made
7
+ after { MenuItem.class_eval {
8
+ ordered_tree # set ordered_tree with no args
9
+ def scope_condition; "1"; end # this is the default scope condition in ordered_tree gem
10
+ } }
11
+
12
+ it "should allow overriding of ordered_tree's scope_condition" do
13
+ MenuItem.class_eval do
14
+ def scope_condition
15
+ "site_id = #{site_id}"
16
+ end
17
+ end
18
+ MenuItem.create(:site_id => 1)
19
+ MenuItem.create(:site_id => 2)
20
+ menu_item = MenuItem.create(:site_id => 1)
21
+ menu_item.position.should == 2
22
+ end
23
+
24
+ it "should allow reconfiguration of ordered_tree" do
25
+ MenuItem.class_eval do
26
+ ordered_tree :scope => :site
27
+ end
28
+ MenuItem.create(:site_id => 3)
29
+ MenuItem.create(:site_id => 4)
30
+ menu_item = MenuItem.create(:site_id => 3)
31
+ menu_item.position.should == 2
32
+ end
33
+ end
34
+
35
+ describe "#label" do
36
+ it "should return the database entry when it exists" do
37
+ MenuItem.new(:label => "Samba").label.should == "Samba"
38
+ end
39
+
40
+ describe "when label field is nil" do
41
+ describe "and there is a navigable model" do
42
+ describe "and there is a specified field" do
43
+ it "should default to the specified field in the navigable model" do
44
+ navigable Category, :label => :nombre do
45
+ c = Category.create :nombre => "Banana"
46
+ nav_item = MenuItem.new(:navigable => c)
47
+ nav_item.label.should == "Banana"
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "and there is no specified field" do
53
+ it "should return nil" do
54
+ c = Category.create
55
+ nav_item = MenuItem.new(:navigable => c)
56
+ nav_item.label.should be_nil
57
+ end
58
+ end
59
+ end
60
+
61
+ describe "and there is no navigable model" do
62
+ it "should return nil" do
63
+ MenuItem.new.label.should == nil
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "#title," do
70
+ describe "when the title field is not nil," do
71
+ it "should return the value in the db" do
72
+ MenuItem.new(:title => "Mambo").title.should == "Mambo"
73
+ end
74
+ end
75
+
76
+ describe "when the title field is nil," do
77
+ describe "and there is a navigable," do
78
+ describe "and :title is set to a string," do
79
+ it "should return the string" do
80
+ navigable Category, :title => "Hola" do
81
+ c = Category.create
82
+ MenuItem.new(:navigable => c).title.should == "Hola"
83
+ end
84
+ end
85
+ end
86
+
87
+ describe "and :title is set to a Symbol," do
88
+ it "should look for the db column and return the value" do
89
+ navigable Category, :title => :nombre do
90
+ c = Category.create :nombre => "Mi nombre"
91
+ MenuItem.new(:navigable => c).title.should == "Mi nombre"
92
+ end
93
+ end
94
+ end
95
+
96
+ describe "and :title is set to a Proc," do
97
+ it "should execute the proc and return the value" do
98
+ navigable Category, :title => Proc.new {|x| "hi_#{x.name}"} do
99
+ c = Category.create :name => "there"
100
+ nav_item = MenuItem.new :navigable => c
101
+ nav_item.title.should == "hi_there"
102
+ end
103
+ end
104
+ end
105
+
106
+ describe "and :title is not set," do
107
+ it "should default to the value of the nav_item's link" do
108
+ c = Category.create
109
+ nav_item = MenuItem.new(:navigable => c)
110
+ nav_item.should_receive(:label).once
111
+ nav_item.title
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ describe "#link" do
119
+ describe "when the link field is not nil," do
120
+ it "should return the value" do
121
+ MenuItem.new(:link => "/holy/moly").link.should == "/holy/moly"
122
+ end
123
+ end
124
+
125
+ describe "when the link field is nil," do
126
+ describe "and there is a nav_item," do
127
+ it "should return the nav_item" do
128
+ # by returning the nav_item we can leave it up to the renderer to convert it to a URL
129
+ c = Category.create
130
+ MenuItem.new(:navigable => c).link.should == c
131
+ end
132
+ end
133
+
134
+ describe "and there is no nav_item," do
135
+ it "should return nil" do
136
+ MenuItem.new.link.should be_nil
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ describe "#highlights_on," do
143
+ describe "when the link field is not nil" do
144
+ it "should return the value converted to regex" do
145
+ MenuItem.new(:highlights_on => "holy").highlights_on.should == /holy/
146
+ end
147
+ end
148
+
149
+ describe "when the link field is nil," do
150
+ it "should return the same value as link" do
151
+ c = Category.create
152
+ nav_item = MenuItem.new(:navigable => c)
153
+ nav_item.highlights_on.should == c
154
+ end
155
+
156
+ describe "and there is a navigable," do
157
+ describe "and the :highlights_on option is set to a string," do
158
+ it "should return that string" do
159
+ navigable Category, :highlights_on => "foobar" do
160
+ c = Category.create
161
+ nav_item = MenuItem.new :navigable => c
162
+ nav_item.highlights_on.should == "foobar"
163
+ end
164
+ end
165
+ end
166
+
167
+ describe "and the :highlights_on option is set to a regexp," do
168
+ it "should return the regexp" do
169
+ navigable Category, :highlights_on => /foobar/ do
170
+ c = Category.create
171
+ nav_item = MenuItem.new :navigable => c
172
+ nav_item.highlights_on.should == /foobar/
173
+ end
174
+ end
175
+ end
176
+
177
+ describe "and the :highlights_on is set to a Proc," do
178
+ it "should execute the Proc on the navigable item and return the value" do
179
+ navigable Category, :highlights_on => Proc.new {|c| "hi_#{c.name}" } do
180
+ c = Category.create :name => "there"
181
+ nav_item = MenuItem.new :navigable => c
182
+ nav_item.highlights_on.should == "hi_there"
183
+ end
184
+ end
185
+ end
186
+
187
+ describe "and the :highlights_on is not set," do
188
+ it "should return the same value as the link" do
189
+ c = Category.create
190
+ nav_item = MenuItem.new(:navigable => c)
191
+ nav_item.highlights_on.should == nav_item.link
192
+ end
193
+ end
194
+ end
195
+
196
+ describe "and there is no navigable," do
197
+ it "should return nil" do
198
+ MenuItem.new.link.should be_nil
199
+ end
200
+ end
201
+ end
202
+
203
+ end
204
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ # SimpleNavigation can accept a array of hashes like so
4
+ #[
5
+ #{:key => :main, :name => 'Main', :url => '/main', :options => {your options here}, :items => [
6
+ #{:key => :sub1, :name => 'Submenu 1', :url => '/sub1'},
7
+ #{:key => :sub2, :name => 'Submenu 2', :url => '/sub2'}
8
+ #]}, {...next primary item...}
9
+ #]
10
+ #
11
+ # That means this is the output we need if we want to get it working with SimpleNavigation.
12
+
13
+ describe Navi::Renderers::SimpleNavigation do
14
+ #class ControllerMock
15
+ #include SimpleNavigation::Helpers
16
+ #end
17
+ #it "should properly convert all the nav items to an array of hashes SimpleNavigation gem can understand" do
18
+ #about = Page.make(:name => "About").to_navigator!
19
+ #home = Page.make(:name => "Home").to_navigator!
20
+ #board_members = Page.make(:name => "Board Members").to_navigator!(:parent_id => about.id)
21
+
22
+ #rendered_navigation = Navi::Renderers::SimpleNavigation.render(MenuItem.roots)
23
+ #rendered_navigation.should == "something"
24
+ #[
25
+ #{
26
+ #:key => :"page_#{about.id}",
27
+ #:name => "About",
28
+ #:url => "/pages/#{about.id}",
29
+ #:options => {},
30
+ #:items => [
31
+ #{
32
+ #:key => :"page_#{board_members.id}",
33
+ #:name => "Board Members",
34
+ #:url => "/pages/#{board_members.id}",
35
+ #:options => {},
36
+ #:items => []
37
+ #}
38
+ #]
39
+ #},
40
+ #{
41
+ #:key => :"page_#{home.id}",
42
+ #:name => "Home",
43
+ #:url => "/pages/#{home.id}",
44
+ #:options => {},
45
+ #:items => []
46
+ #}
47
+ #]
48
+ #end
49
+ end