spaghetti 0.2.6

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 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: []