spaghetti 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in spaghetti.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Omar Abdel-Wahab
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # Spaghetti
2
+
3
+ Endless page for Rails > 3.1 using jQuery Sausage.
4
+ Spaghetti supports both [Kaminari](https://github.com/amatsuda/kaminari) and [will_paginate](https://github.com/mislav/will_paginate).
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'spaghetti'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install spaghetti
19
+
20
+ ## Usage
21
+
22
+ Make sure you add spaghetti JavaScript to your `application.js`:
23
+
24
+ //= require spaghetti
25
+
26
+ Then add spaghetti markup to your view (example: posts/index.html):
27
+
28
+ <%= spaghetti 'posts', posts_path %>
29
+
30
+ You need to have your `posts_controller` responding with the following `index.js.erb` file:
31
+
32
+ <%= spaghetti 'posts', @posts %>
33
+
34
+
35
+ ## Contributing
36
+
37
+ 1. Fork it
38
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
39
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
40
+ 4. Push to the branch (`git push origin my-new-feature`)
41
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,20 @@
1
+ module SpaghettiHelpers
2
+ def spaghetti name, path_or_items
3
+ output = ''.html_safe
4
+ puts path_or_items.class.name
5
+ if path_or_items.class.name == 'String'
6
+ output << "<div class=\"#{ name } spaghetti\" data-spaghetti-enabled=\"1\" data-spaghetti-url=\"#{ path_or_items }\" data-spaghetti-next-page=\"1\"><div class=\"items\"></div><div class=\"throbber\">#{ image_tag 'throbber.gif' }</div></div>".html_safe
7
+ else
8
+ if path_or_items.any?
9
+ output << "$('.#{ name } .items').append('#{ j render path_or_items }');".html_safe
10
+ output << "$('.#{ name }').data('spaghetti-next-page', #{ params[:page].to_i + 1 });".html_safe
11
+ output << "$('.#{ name }').data('spaghetti-enabled', '1');".html_safe
12
+ else
13
+ output << "$('.#{ name }').data('spaghetti-enabled', '0');".html_safe
14
+ output << "$('.#{ name }').append($('<div class=\"spaghetti-disabled\"></div>'));".html_safe
15
+ end
16
+ output << "$('.#{ name }').removeClass('spaghetti-loading');".html_safe
17
+ end
18
+ output
19
+ end
20
+ end
data/lib/spaghetti.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "spaghetti/version"
2
+ require "spaghetti/engine"
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/../../app/helpers/spaghetti_helpers'
2
+
3
+ module Spaghetti
4
+ class Engine < ::Rails::Engine
5
+ initializer "spaghetti.setup_helpers" do |app|
6
+ app.config.to_prepare do
7
+ ActionController::Base.send :helper, SpaghettiHelpers
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Spaghetti
2
+ VERSION = "0.2.6"
3
+ end
data/spaghetti.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'spaghetti/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "spaghetti"
8
+ gem.version = Spaghetti::VERSION
9
+ gem.platform = Gem::Platform::RUBY
10
+ gem.authors = ["Omar Abdel-Wahab"]
11
+ gem.email = ["owahab@gmail.com"]
12
+ gem.description = %q{Spaghetti - Rails Endless Page}
13
+ gem.summary = %q{Spaghetti - Rails Endless Page}
14
+ gem.homepage = "http://github.com/owahab/spaghetti"
15
+ gem.add_dependency 'jquery-rails', '>= 2.1'
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+ end
Binary file
@@ -0,0 +1,4 @@
1
+ //= require jquery
2
+ //= require jquery-ui
3
+ //= require spaghetti/jquery.sausage
4
+ //= require spaghetti/init
@@ -0,0 +1,23 @@
1
+ $(function() {
2
+ function nearBottomOfPage() {
3
+ return $(window).scrollTop() > $(document).height() - $(window).height() - 200;
4
+ }
5
+
6
+ $(window).scroll(function(){
7
+ if ($('.spaghetti').data('spaghetti-enabled') == 1) {
8
+ if(nearBottomOfPage()) {
9
+ $('.spaghetti').data('spaghetti-enabled', 0);
10
+ $('.spaghetti').addClass('spaghetti-loading');
11
+ $.ajax({
12
+ url: $('.spaghetti').data('spaghetti-url') + '?page=' + $('.spaghetti').data('spaghetti-next-page'),
13
+ type: 'get',
14
+ dataType: 'script',
15
+ success: function() {
16
+ $(window).sausage('draw');
17
+ }
18
+ });
19
+ }
20
+ }
21
+ });
22
+ $(window).sausage();
23
+ });
@@ -0,0 +1,428 @@
1
+ // jquery.sausage.js 1.0.0
2
+ // (c) 2011 Christopher Cliff
3
+ // Freely distributed under the MIT license.
4
+ // For all details and documentation:
5
+ // http://christophercliff.github.com/sausage
6
+
7
+ (function($, undefined){
8
+
9
+ $.widget('cc.sausage', {
10
+
11
+ // # Options
12
+ //
13
+ //
14
+
15
+ options: {
16
+
17
+ // ### page `string`
18
+ //
19
+ // Sets the string to be used to select page elements.
20
+ //
21
+ // Example:
22
+ //
23
+ // $(window)
24
+ // .sausage({
25
+ // page: '.my-page-selector'
26
+ // })
27
+ // ;
28
+ //
29
+ page: '.page',
30
+
31
+ // ### content `function`
32
+ //
33
+ // Sets the content of the sausage elements. Use `i` and `$page` to render content dynamically.
34
+ //
35
+ // Example:
36
+ //
37
+ // $(window)
38
+ // .sausage({
39
+ // content: function (i, $page) {
40
+ // return '<div>' + $page.data('name') + '</div>';
41
+ // }
42
+ // })
43
+ // ;
44
+ //
45
+ content: function (i, $page) {
46
+ return '<span class="sausage-span">' + (i + 1) + '</span>';
47
+ }
48
+
49
+ },
50
+
51
+ // # Private Methods
52
+ //
53
+ //
54
+
55
+ // ## `._create()`
56
+ //
57
+ //
58
+ _create: function () {
59
+
60
+ var self = this,
61
+ $el = self.element;
62
+
63
+ // Use $el for the outer element.
64
+ self.$outer = $el;
65
+ // Use `body` for the inner element if the outer element is `window`. Otherwise, use the first child of `$el`.
66
+ self.$inner = $.isWindow(self.element.get(0)) ? $('body') : $el.children(':first-child');
67
+ self.$sausages = $('<div class="sausage-set"/>');
68
+ self.sausages = self.$sausages.get(0);
69
+ self.offsets = [];
70
+
71
+ self.$sausages
72
+ .appendTo(self.$inner)
73
+ ;
74
+
75
+ // Trigger the `create` event.
76
+ self._trigger('create');
77
+
78
+ return;
79
+ },
80
+
81
+ // ## `._init()`
82
+ //
83
+ //
84
+ _init: function () {
85
+
86
+ var self = this;
87
+
88
+ // Stop and destroy if scroll bar is not present.
89
+ if (self.$outer.height() >= self.$inner.height())
90
+ {
91
+ self.destroy();
92
+
93
+ return;
94
+ }
95
+
96
+ self.draw();
97
+ self._update();
98
+ self._events();
99
+ self._delegates();
100
+
101
+ // Add a CSS class for styling purposes.
102
+ self.$sausages
103
+ .addClass('sausage-set-init')
104
+ ;
105
+
106
+ self.blocked = false;
107
+
108
+ // Trigger the `init` event.
109
+ self._trigger('init');
110
+
111
+ return;
112
+ },
113
+
114
+ // ## `._events()`
115
+ //
116
+ //
117
+ _events: function () {
118
+
119
+ var self = this;
120
+
121
+ self.hasScrolled = false;
122
+
123
+ self.$outer
124
+ .bind('resize.sausage', function(){
125
+
126
+ self.draw();
127
+
128
+ })
129
+ .bind('scroll.sausage', function(e){
130
+
131
+ self.hasScrolled = true;
132
+
133
+ })
134
+ ;
135
+
136
+ // [Prevent crazy amounts of scroll events from being fired](http://ejohn.org/blog/learning-from-twitter/) by setting an interval and listening.
137
+ setInterval(function(){
138
+
139
+ if (!self.hasScrolled)
140
+ {
141
+ return;
142
+ }
143
+
144
+ self.hasScrolled = false;
145
+ self._update();
146
+
147
+ }, 250);
148
+
149
+ return;
150
+ },
151
+
152
+ // ## `._getCurrent()`
153
+ //
154
+ //
155
+ _getCurrent: function () {
156
+
157
+ var self = this,
158
+ st = self.$outer.scrollTop() + self._getHandleHeight(self.$outer, self.$inner)/4,
159
+ h_win = self.$outer.height(),
160
+ h_doc = self.$inner.height(),
161
+ i = 0;
162
+
163
+ for (l = self.offsets.length; i < l; i++)
164
+ {
165
+ if (!self.offsets[i + 1])
166
+ {
167
+ return i;
168
+ }
169
+ else if (st <= self.offsets[i])
170
+ {
171
+ return i;
172
+ }
173
+ else if (st > self.offsets[i] && st <= self.offsets[i + 1])
174
+ {
175
+ return i;
176
+ }
177
+ }
178
+
179
+ return i;
180
+ },
181
+
182
+ // ## `._delegates()`
183
+ //
184
+ //
185
+ _delegates: function () {
186
+
187
+ var self = this;
188
+
189
+ self.$sausages
190
+ .delegate('.sausage', 'hover', function(){
191
+
192
+ if (self.blocked)
193
+ {
194
+ return;
195
+ }
196
+
197
+ $(this)
198
+ .toggleClass('sausage-hover')
199
+ ;
200
+
201
+ })
202
+ .delegate('.sausage', 'click', function(e){
203
+ e.preventDefault();
204
+
205
+ if (self.blocked)
206
+ {
207
+ return;
208
+ }
209
+
210
+ var $sausage = $(this),
211
+ val = $sausage.index(),
212
+ o = self.$inner.find(self.options.page).eq(val).offset().top;
213
+
214
+ self._scrollTo(o);
215
+
216
+ // Trigger the `onClick` event.
217
+ //
218
+ // Example:
219
+ //
220
+ // $(window)
221
+ // .sausage({
222
+ // onClick: function (e, o) {
223
+ // alert('You clicked the sausage at index: ' + o.i);
224
+ // }
225
+ // })
226
+ // ;
227
+ //
228
+ self._trigger('onClick', e, {
229
+ $sausage: $sausage,
230
+ i: val
231
+ });
232
+
233
+ if ($sausage.hasClass('current'))
234
+ {
235
+ return;
236
+ }
237
+
238
+ // Trigger the `onUpdate` event.
239
+ self._trigger('onUpdate', e, {
240
+ $sausage: $sausage,
241
+ i: val
242
+ });
243
+ })
244
+ ;
245
+
246
+ return;
247
+ },
248
+
249
+ _scrollTo: function (o) {
250
+
251
+ var self = this,
252
+ $outer = self.$outer,
253
+ rate = 2/1, // px/ms
254
+ distance = self.offsets[self.current] - o,
255
+ duration = Math.abs(distance/rate);
256
+ // Travel at 2 px per 1 ms but never longer than 1 s.
257
+ duration = (duration < 1000) ? duration : 1000;
258
+
259
+ if (self.$outer.get(0) === window)
260
+ {
261
+ $outer = $('body, html, document');
262
+ }
263
+
264
+ $outer
265
+ .stop(true)
266
+ .animate({
267
+ scrollTop: o
268
+ }, duration)
269
+ ;
270
+
271
+ return;
272
+ },
273
+
274
+ _handleClick: function () {
275
+
276
+ var self = this
277
+
278
+
279
+
280
+ return;
281
+ },
282
+
283
+ // ## `._update()`
284
+ //
285
+ //
286
+ _update: function () {
287
+
288
+ var self = this;
289
+ i = self._getCurrent(),
290
+ c = 'sausage-current';
291
+
292
+ if (i === self.current || self.blocked)
293
+ {
294
+ return;
295
+ }
296
+
297
+ self.current = i;
298
+
299
+ self.$sausages.children().eq(i)
300
+ .addClass(c)
301
+ .siblings()
302
+ .removeClass(c)
303
+ ;
304
+
305
+ // Trigger the `update` event.
306
+ self._trigger('update');
307
+
308
+ return;
309
+ },
310
+
311
+ // ### `._getHandleHeight()`
312
+ //
313
+ //
314
+ _getHandleHeight: function ($outer, $inner) {
315
+
316
+ var h_outer = $outer.height(),
317
+ h_inner = $inner.height();
318
+
319
+ return h_outer/h_inner*h_outer;
320
+ },
321
+
322
+ // # Public Methods
323
+ //
324
+ //
325
+
326
+ // ### draw `.sausage("draw")`
327
+ //
328
+ // Creates the sausage UI elements.
329
+ draw: function () {
330
+
331
+ var self = this,
332
+ h_win = self.$outer.height(),
333
+ h_doc = self.$inner.height(),
334
+ $items = self.$inner.find(self.options.page),
335
+ $page,
336
+ s = [],
337
+ offset_p,
338
+ offset_s;
339
+
340
+ self.offsets = [];
341
+ self.count = $items.length;
342
+
343
+ // Detach from DOM while making changes.
344
+ self.$sausages
345
+ .detach()
346
+ .empty()
347
+ ;
348
+
349
+ // Calculate the element heights and push to an array.
350
+ for (var i = 0; i < self.count; i++)
351
+ {
352
+ $page = $items.eq(i);
353
+ offset_p = $page.offset();
354
+ offset_s = offset_p.top/h_doc*h_win;
355
+
356
+ s.push('<div class="sausage' + ((i === self.current) ? ' sausage-current' : '') + '" style="height:' + ($page.outerHeight()/h_doc*h_win) + 'px;top:' + offset_s + 'px;">' + self.options.content(i, $page) + '</div>');
357
+
358
+ // Create `self.offsets` for calculating current sausage.
359
+ self.offsets.push(offset_p.top);
360
+ }
361
+
362
+ // Use Array.join() for speed.
363
+ self.sausages.innerHTML = s.join('');
364
+
365
+ // And reattach.
366
+ self.$sausages
367
+ .appendTo(self.$inner)
368
+ ;
369
+
370
+ return;
371
+ },
372
+
373
+ // ### block `.sausage("block")`
374
+ //
375
+ // Blocks the UI to prevent users from interacting with the sausage UI. Useful when loading data and updating the DOM.
376
+ block: function () {
377
+
378
+ var self = this,
379
+ c = 'sausage-set-blocked';
380
+
381
+ self.blocked = true;
382
+
383
+ // Add a CSS class for styling purposes.
384
+ self.$sausages
385
+ .addClass(c)
386
+ ;
387
+
388
+ return;
389
+ },
390
+
391
+ // ### unblock `.sausage("unblock")`
392
+ //
393
+ // Unblocks the UI once loading and DOM manipulation are complete.
394
+ unblock: function () {
395
+
396
+ var self = this,
397
+ c = 'sausage-set-blocked';
398
+
399
+ self.$sausages
400
+ .removeClass(c)
401
+ ;
402
+
403
+ self.blocked = false;
404
+
405
+ return;
406
+ },
407
+
408
+ // ### destroy `.sausage("destroy")`
409
+ //
410
+ // Removes the sausage instance from the DOM.
411
+ destroy: function () {
412
+
413
+ var self = this;
414
+
415
+ self.$outer
416
+ .unbind('.sausage')
417
+ ;
418
+
419
+ self.$sausages
420
+ .remove()
421
+ ;
422
+
423
+ return;
424
+ }
425
+
426
+ });
427
+
428
+ })(jQuery);
@@ -0,0 +1,12 @@
1
+ .throbber {
2
+ display: none;
3
+ text-align: center;
4
+ }
5
+
6
+ .spaghetti-loading > .throbber {
7
+ display: block;
8
+ }
9
+
10
+ .spaghetti-disabled {
11
+ padding: 20px;
12
+ }
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spaghetti
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.6
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Omar Abdel-Wahab
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: jquery-rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '2.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '2.1'
30
+ description: Spaghetti - Rails Endless Page
31
+ email:
32
+ - owahab@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE.txt
40
+ - README.md
41
+ - Rakefile
42
+ - app/helpers/spaghetti_helpers.rb
43
+ - lib/spaghetti.rb
44
+ - lib/spaghetti/engine.rb
45
+ - lib/spaghetti/version.rb
46
+ - spaghetti.gemspec
47
+ - vendor/assets/images/throbber.gif
48
+ - vendor/assets/javascripts/spaghetti.js
49
+ - vendor/assets/javascripts/spaghetti/init.js
50
+ - vendor/assets/javascripts/spaghetti/jquery.sausage.js
51
+ - vendor/assets/stylesheets/spaghetti.css
52
+ homepage: http://github.com/owahab/spaghetti
53
+ licenses: []
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ segments:
65
+ - 0
66
+ hash: 2528948971779599297
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ segments:
74
+ - 0
75
+ hash: 2528948971779599297
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 1.8.24
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Spaghetti - Rails Endless Page
82
+ test_files: []