├── log
└── .gitkeep
├── lib
└── tasks
│ └── .gitkeep
├── public
├── favicon.ico
├── robots.txt
├── 422.html
├── 404.html
└── 500.html
├── test
├── unit
│ ├── .gitkeep
│ ├── helpers
│ │ └── pages_helper_test.rb
│ └── page_test.rb
├── fixtures
│ ├── .gitkeep
│ └── pages.yml
├── functional
│ ├── .gitkeep
│ └── pages_controller_test.rb
├── integration
│ └── .gitkeep
├── performance
│ └── browsing_test.rb
└── test_helper.rb
├── app
├── mailers
│ └── .gitkeep
├── models
│ ├── .gitkeep
│ └── page.rb
├── helpers
│ └── application_helper.rb
├── assets
│ ├── javascripts
│ │ ├── app
│ │ │ ├── views
│ │ │ │ └── pages
│ │ │ │ │ ├── item.jst.eco
│ │ │ │ │ └── list.jst.eco
│ │ │ ├── index.coffee
│ │ │ ├── models
│ │ │ │ └── page.coffee
│ │ │ ├── controllers
│ │ │ │ └── pages.coffee
│ │ │ └── lib
│ │ │ │ └── jquery.waypoints.js
│ │ └── application.js
│ ├── images
│ │ └── rails.png
│ └── stylesheets
│ │ ├── pages.css
│ │ └── application.css
├── controllers
│ ├── application_controller.rb
│ └── pages_controller.rb
└── views
│ └── pages
│ └── index.html.erb
├── vendor
├── plugins
│ └── .gitkeep
└── assets
│ └── stylesheets
│ └── .gitkeep
├── Procfile
├── .gitignore
├── config.ru
├── config
├── environment.rb
├── boot.rb
├── initializers
│ ├── mime_types.rb
│ ├── stitch.rb
│ ├── inflections.rb
│ ├── backtrace_silencers.rb
│ ├── session_store.rb
│ ├── secret_token.rb
│ └── wrap_parameters.rb
├── locales
│ └── en.yml
├── database.yml
├── environments
│ ├── development.rb
│ ├── test.rb
│ └── production.rb
├── routes.rb
└── application.rb
├── doc
└── README_FOR_APP
├── db
├── migrate
│ └── 20110616103504_create_pages.rb
├── seeds.rb
└── schema.rb
├── Rakefile
├── script
└── rails
├── Gemfile
├── README.md
└── Gemfile.lock
/log/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/tasks/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/unit/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/mailers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/models/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/fixtures/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/plugins/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/functional/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/integration/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: bundle exec rails server thin -p $PORT
2 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/assets/javascripts/app/views/pages/item.jst.eco:
--------------------------------------------------------------------------------
1 |
<%= @name %>
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle
2 | db/*.sqlite3
3 | log/*.log
4 | tmp/
5 | .sass-cache/
6 | .DS_Store
7 |
--------------------------------------------------------------------------------
/app/models/page.rb:
--------------------------------------------------------------------------------
1 | class Page < ActiveRecord::Base
2 | validates_presence_of :name
3 | end
--------------------------------------------------------------------------------
/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | //= require jquery
2 | //= require jquery_ujs
3 | //= require app/index
--------------------------------------------------------------------------------
/app/assets/images/rails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maccman/spine.infinite/HEAD/app/assets/images/rails.png
--------------------------------------------------------------------------------
/test/unit/helpers/pages_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class PagesHelperTest < ActionView::TestCase
4 | end
5 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery
3 | end
4 |
--------------------------------------------------------------------------------
/test/unit/page_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class PageTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/app/assets/javascripts/app/views/pages/list.jst.eco:
--------------------------------------------------------------------------------
1 | Pages
2 |
3 |
4 |
5 | Loading...
6 |
7 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run SpineRails3::Application
5 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the rails application
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the rails application
5 | SpineRails3::Application.initialize!
6 |
--------------------------------------------------------------------------------
/test/functional/pages_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class PagesControllerTest < ActionController::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 |
3 | # Set up gems listed in the Gemfile.
4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
5 |
6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
7 |
--------------------------------------------------------------------------------
/doc/README_FOR_APP:
--------------------------------------------------------------------------------
1 | Use this README file to introduce your application and point to useful places in the API for learning more.
2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
3 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
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: /
6 |
--------------------------------------------------------------------------------
/app/assets/javascripts/app/index.coffee:
--------------------------------------------------------------------------------
1 | #= require json2
2 | #= require jquery
3 | #= require spine
4 | #= require spine/ajax
5 | #
6 | #= require_tree ./lib
7 | #= require_tree ./models
8 | #= require_tree ./controllers
9 | #= require_tree ./views
--------------------------------------------------------------------------------
/app/controllers/pages_controller.rb:
--------------------------------------------------------------------------------
1 | class PagesController < ApplicationController
2 | respond_to :html, :json
3 |
4 | def index
5 | @pages = Page.where("id > ?", params[:index] || 0).limit(60)
6 | respond_with(@pages)
7 | end
8 | end
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 | # Mime::Type.register_alias "text/html", :iphone
6 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Sample localization file for English. Add more files in this directory for other locales.
2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3 |
4 | en:
5 | hello: "Hello world"
6 |
--------------------------------------------------------------------------------
/test/fixtures/pages.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html
2 |
3 | one:
4 | name: MyString
5 | slug: MyString
6 | body: MyText
7 |
8 | two:
9 | name: MyString
10 | slug: MyString
11 | body: MyText
12 |
--------------------------------------------------------------------------------
/db/migrate/20110616103504_create_pages.rb:
--------------------------------------------------------------------------------
1 | class CreatePages < ActiveRecord::Migration
2 | def change
3 | create_table :pages do |t|
4 | t.string :name
5 | t.string :slug
6 | t.text :body
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env rake
2 | # Add your own tasks in files placed in lib/tasks ending in .rake,
3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4 |
5 | require File.expand_path('../config/application', __FILE__)
6 |
7 | SpineRails3::Application.load_tasks
8 |
--------------------------------------------------------------------------------
/config/initializers/stitch.rb:
--------------------------------------------------------------------------------
1 | class StitchApplication
2 | def initialize
3 | @package = Stitch::Package.new(:paths => ["app/assets/javascripts/app", "app/assets/javascripts/lib"])
4 | end
5 |
6 | def call(env)
7 | [200, {"Content-Type" => "text/javascript"}, [Uglifier.compile(@package.compile)]]
8 | end
9 | end
--------------------------------------------------------------------------------
/script/rails:
--------------------------------------------------------------------------------
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'
7 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'http://rubygems.org'
2 |
3 | gem 'rails', '3.1.0'
4 |
5 | group :assets do
6 | gem 'coffee-rails'
7 | gem 'uglifier'
8 | gem 'sass'
9 | end
10 |
11 | gem 'jquery-rails'
12 | gem 'eco'
13 | gem 'spine-rails'
14 | gem 'thin'
15 |
16 | group :development do
17 | gem 'sqlite3'
18 | gem 'ruby-debug19', :require => 'ruby-debug'
19 | end
20 |
21 | group :production do
22 | gem 'pg'
23 | end
--------------------------------------------------------------------------------
/app/assets/javascripts/app/models/page.coffee:
--------------------------------------------------------------------------------
1 | class Page extends Spine.Model
2 | @configure "Page", "name"
3 | @extend Spine.Model.Ajax.Methods
4 |
5 | @fetch (params) ->
6 | index = @last()?.id or 0
7 | return false if index is @index
8 | @index = index
9 |
10 | params or=
11 | data: {index: index}
12 | processData: true
13 |
14 | @ajax().fetch(params)
15 |
16 | window.Page = Page
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format
4 | # (all these examples are active by default):
5 | # ActiveSupport::Inflector.inflections do |inflect|
6 | # inflect.plural /^(ox)$/i, '\1en'
7 | # inflect.singular /^(ox)en/i, '\1'
8 | # inflect.irregular 'person', 'people'
9 | # inflect.uncountable %w( fish sheep )
10 | # end
11 |
--------------------------------------------------------------------------------
/test/performance/browsing_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 | require 'rails/performance_test_help'
3 |
4 | class BrowsingTest < ActionDispatch::PerformanceTest
5 | # Refer to the documentation for all available options
6 | # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory]
7 | # :output => 'tmp/performance', :formats => [:flat] }
8 |
9 | def test_homepage
10 | get '/'
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/views/pages/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Infinite
5 | <%= stylesheet_link_tag "application" %>
6 | <%= javascript_include_tag "application" %>
7 | <%= csrf_meta_tags %>
8 |
9 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | SpineRails3::Application.config.session_store :cookie_store, key: '_spine.rails3_session'
4 |
5 | # Use the database for sessions instead of the cookie-based default,
6 | # which shouldn't be used to store highly confidential information
7 | # (create the session table with "rails generate session_migration")
8 | # SpineRails3::Application.config.session_store :active_record_store
9 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RAILS_ENV"] = "test"
2 | require File.expand_path('../../config/environment', __FILE__)
3 | require 'rails/test_help'
4 |
5 | class ActiveSupport::TestCase
6 | # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
7 | #
8 | # Note: You'll currently still have to declare fixtures explicitly in integration tests
9 | # -- they do not yet inherit this setting
10 | fixtures :all
11 |
12 | # Add more helper methods to be used by all tests here...
13 | end
14 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
7 | # Mayor.create(name: 'Emanuel', city: cities.first)
8 |
9 | 1000.times do |i|
10 | page = Page.new
11 | page.name = "A Page"
12 | page.save!
13 | page.name = "A Page ##{page.id}"
14 | page.save!
15 | end
--------------------------------------------------------------------------------
/config/initializers/secret_token.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 | # Make sure the secret is at least 30 characters and all random,
6 | # no regular words or you'll be exposed to dictionary attacks.
7 | SpineRails3::Application.config.secret_token = '877d90109fe035a16ac02b3e7ff4969bb5d53b8f58ca5e1b7ad0ce630b225318f0bf647e6fd8681274df726e1fae55815b815194f8bc93d873357d37dae4ac77'
8 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 | #
3 | # This file contains the settings for ActionController::ParametersWrapper
4 | # which will be enabled by default in the upcoming version of Ruby on Rails.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActionController::Base.wrap_parameters format: [:json]
8 |
9 | # Disable root element in JSON by default.
10 | if defined?(ActiveRecord)
11 | ActiveRecord::Base.include_root_in_json = false
12 | end
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ##Introduction
2 |
3 | This is an example of infinite scrolling using [Spine](http://spinejs.com) and Rails.
4 |
5 | You can find a live demo [here](http://spine-infinite.herokuapp.com/).
6 |
7 | ##Source
8 |
9 | The files you need to inspect are:
10 |
11 | * `app/assets/javascripts/app/models/page.coffee`
12 | * `app/assets/javascripts/app/controllers/pages.coffee`
13 | * `app/controllers/pages_controller.rb`
14 |
15 | ##Usage
16 |
17 | bundle install
18 | rake db:setup
19 | rake db:seed
20 |
21 | rails server thin
22 |
23 | open http://localhost:3000
--------------------------------------------------------------------------------
/app/assets/stylesheets/pages.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | overflow: auto;
3 | }
4 |
5 | #pages {
6 | overflow: none;
7 | margin: 20px;
8 |
9 | padding: 20px;
10 | background: #FFF;
11 | -webkit-box-shadow: rgba(100, 100, 100, 0.3) 0 2px 6px;
12 | -moz-box-shadow: rgba(100, 100, 100, 0.3) 0 2px 6px;
13 | box-shadow: rgba(100, 100, 100, 0.3) 0 2px 6px;
14 | }
15 |
16 | #pages .loading {
17 | position: fixed;
18 | right: 20px;
19 | bottom: 10px;
20 | padding: 5px;
21 | background: #ffffcc;
22 | opacity: 0;
23 | -webkit-transition: opacity 0.5s linear;
24 | }
25 |
26 | #pages.loading .loading {
27 | opacity: 1;
28 | }
29 |
30 | #pages h1 {
31 | margin: 0 0 8px 0;
32 | }
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | development:
7 | adapter: sqlite3
8 | database: db/development.sqlite3
9 | pool: 5
10 | timeout: 5000
11 |
12 | # Warning: The database defined as "test" will be erased and
13 | # re-generated from your development database when you run "rake".
14 | # Do not set this db to the same as development or production.
15 | test:
16 | adapter: sqlite3
17 | database: db/test.sqlite3
18 | pool: 5
19 | timeout: 5000
20 |
21 | production:
22 | adapter: sqlite3
23 | database: db/production.sqlite3
24 | pool: 5
25 | timeout: 5000
26 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The change you wanted was rejected.
23 |
Maybe you tried to change something you didn't have access to.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/assets/javascripts/app/controllers/pages.coffee:
--------------------------------------------------------------------------------
1 | $ = jQuery
2 |
3 | class Pages extends Spine.Controller
4 | className: 'list'
5 |
6 | elements:
7 | '.items': 'items'
8 | 'footer': 'footer'
9 |
10 | constructor: ->
11 | super
12 |
13 | @html JST['app/views/pages/list']()
14 |
15 | Page.bind 'fetch', =>
16 | @el.addClass('loading')
17 |
18 | Page.bind 'refresh', =>
19 | @el.removeClass('loading')
20 | @footer.waypoint(@scroll, offset: '80%')
21 | @render(arguments...)
22 |
23 | Page.fetch()
24 |
25 | render: (items = []) =>
26 | for item in items
27 | @items.append JST['app/views/pages/item'](item)
28 |
29 | scroll: (e, direction) =>
30 | @footer.waypoint('destroy')
31 | Page.fetch()
32 |
33 | window.Pages = Pages
34 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The page you were looking for doesn't exist.
23 |
You may have mistyped the address or the page may have moved.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
We're sorry, but something went wrong.
23 |
We've been notified about this issue and we'll take a look at it shortly.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/db/schema.rb:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from the current state of the database. Instead
2 | # of editing this file, please use the migrations feature of Active Record to
3 | # incrementally modify your database, and then regenerate this schema definition.
4 | #
5 | # Note that this schema.rb definition is the authoritative source for your
6 | # database schema. If you need to create the application database on another
7 | # system, you should be using db:schema:load, not running all the migrations
8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 | # you'll amass, the slower it'll run and the greater likelihood for issues).
10 | #
11 | # It's strongly recommended to check this file into your version control system.
12 |
13 | ActiveRecord::Schema.define(:version => 20110616103504) do
14 |
15 | create_table "pages", :force => true do |t|
16 | t.string "name"
17 | t.string "slug"
18 | t.text "body"
19 | t.datetime "created_at"
20 | t.datetime "updated_at"
21 | end
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | SpineRails3::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Log error messages when you accidentally call methods on nil.
10 | config.whiny_nils = true
11 |
12 | # Show full error reports and disable caching
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | # Don't care if the mailer can't send
17 | config.action_mailer.raise_delivery_errors = false
18 |
19 | # Print deprecation notices to the Rails logger
20 | config.active_support.deprecation = :log
21 |
22 | # Only use best-standards-support built into browsers
23 | config.action_dispatch.best_standards_support = :builtin
24 | end
25 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | SpineRails3::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Configure static asset server for tests with Cache-Control for performance
11 | config.serve_static_assets = true
12 | config.static_cache_control = "public, max-age=3600"
13 |
14 | # Log error messages when you accidentally call methods on nil
15 | config.whiny_nils = true
16 |
17 | # Show full error reports and disable caching
18 | config.consider_all_requests_local = true
19 | config.action_controller.perform_caching = false
20 |
21 | # Raise exceptions instead of rendering exception templates
22 | config.action_dispatch.show_exceptions = false
23 |
24 | # Disable request forgery protection in test environment
25 | config.action_controller.allow_forgery_protection = false
26 |
27 | # Tell Action Mailer not to deliver emails to the real world.
28 | # The :test delivery method accumulates sent emails in the
29 | # ActionMailer::Base.deliveries array.
30 | config.action_mailer.delivery_method = :test
31 |
32 | # Use SQL instead of Active Record's schema dumper when creating the test database.
33 | # This is necessary if your schema can't be completely dumped by the schema dumper,
34 | # like if you have constraints or database-specific column types
35 | # config.active_record.schema_format = :sql
36 |
37 | # Print deprecation notices to the stderr
38 | config.active_support.deprecation = :stderr
39 | end
40 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | SpineRails3::Application.routes.draw do
2 | # The priority is based upon order of creation:
3 | # first created -> highest priority.
4 |
5 | # Sample of regular route:
6 | # match 'products/:id' => 'catalog#view'
7 | # Keep in mind you can assign values other than :controller and :action
8 |
9 | # Sample of named route:
10 | # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
11 | # This route can be invoked with purchase_url(:id => product.id)
12 |
13 | # Sample resource route (maps HTTP verbs to controller actions automatically):
14 | # resources :products
15 |
16 | # Sample resource route with options:
17 | # resources :products do
18 | # member do
19 | # get 'short'
20 | # post 'toggle'
21 | # end
22 | #
23 | # collection do
24 | # get 'sold'
25 | # end
26 | # end
27 |
28 | # Sample resource route with sub-resources:
29 | # resources :products do
30 | # resources :comments, :sales
31 | # resource :seller
32 | # end
33 |
34 | # Sample resource route with more complex sub-resources
35 | # resources :products do
36 | # resources :comments
37 | # resources :sales do
38 | # get 'recent', :on => :collection
39 | # end
40 | # end
41 |
42 | # Sample resource route within a namespace:
43 | # namespace :admin do
44 | # # Directs /admin/products/* to Admin::ProductsController
45 | # # (app/controllers/admin/products_controller.rb)
46 | # resources :products
47 | # end
48 |
49 | # You can have the root of your site routed with "root"
50 | # just remember to delete public/index.html.
51 | # root :to => 'welcome#index'
52 |
53 | # See how all your routes lay out with "rake routes"
54 |
55 | resources :pages
56 |
57 | root :to => 'pages#index'
58 |
59 | # This is a legacy wild controller route that's not recommended for RESTful applications.
60 | # Note: This route will make all actions in every controller accessible via GET requests.
61 | # match ':controller(/:action(/:id(.:format)))'
62 | end
63 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | SpineRails3::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # Code is not reloaded between requests
5 | config.cache_classes = true
6 |
7 | # Full error reports are disabled and caching is turned on
8 | config.consider_all_requests_local = false
9 | config.action_controller.perform_caching = true
10 |
11 | # Disable Rails's static asset server (Apache or nginx will already do this)
12 | config.serve_static_assets = false
13 |
14 | # Compress both stylesheets and JavaScripts
15 | config.assets.js_compressor = :uglifier
16 | config.assets.css_compressor = :scss
17 |
18 | # Specifies the header that your server uses for sending files
19 | # (comment out if your front-end server doesn't support this)
20 | config.action_dispatch.x_sendfile_header = "X-Sendfile" # Use 'X-Accel-Redirect' for nginx
21 |
22 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
23 | # config.force_ssl = true
24 |
25 | # See everything in the log (default is :info)
26 | # config.log_level = :debug
27 |
28 | # Use a different logger for distributed setups
29 | # config.logger = SyslogLogger.new
30 |
31 | # Use a different cache store in production
32 | # config.cache_store = :mem_cache_store
33 |
34 | # Enable serving of images, stylesheets, and JavaScripts from an asset server
35 | # config.action_controller.asset_host = "http://assets.example.com"
36 |
37 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
38 | # config.assets.precompile += %w( search.js )
39 |
40 | # Disable delivery errors, bad email addresses will be ignored
41 | # config.action_mailer.raise_delivery_errors = false
42 |
43 | # Enable threaded mode
44 | # config.threadsafe!
45 |
46 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
47 | # the I18n.default_locale when a translation can not be found)
48 | config.i18n.fallbacks = true
49 |
50 | # Send deprecation notices to registered listeners
51 | config.active_support.deprecation = :notify
52 | end
53 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 |
5 | # If you have a Gemfile, require the gems listed there, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(:default, Rails.env) if defined?(Bundler)
8 |
9 | module SpineRails3
10 | class Application < Rails::Application
11 | # Settings in config/environments/* take precedence over those specified here.
12 | # Application configuration should go into files in config/initializers
13 | # -- all .rb files in that directory are automatically loaded.
14 |
15 | # Custom directories with classes and modules you want to be autoloadable.
16 | # config.autoload_paths += %W(#{config.root}/extras)
17 |
18 | # Only load the plugins named here, in the order given (default is alphabetical).
19 | # :all can be used as a placeholder for all plugins not explicitly named.
20 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
21 |
22 | # Activate observers that should always be running.
23 | # config.active_record.observers = :my_observer
24 |
25 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
26 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
27 | # config.time_zone = 'Central Time (US & Canada)'
28 |
29 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
30 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
31 | # config.i18n.default_locale = :de
32 |
33 | # Please note that JavaScript expansions are *ignored altogether* if the asset
34 | # pipeline is enabled (see config.assets.enabled below). Put your defaults in
35 | # app/assets/javascripts/application.js in that case.
36 | #
37 | # JavaScript files you want as :defaults (application.js is always included).
38 | # config.action_view.javascript_expansions[:defaults] = %w(prototype prototype_ujs)
39 |
40 | # Configure the default encoding used in templates for Ruby 1.9.
41 | config.encoding = "utf-8"
42 |
43 | # Configure sensitive parameters which will be filtered from the log file.
44 | config.filter_parameters += [:password]
45 |
46 | # Enable the asset pipeline
47 | config.assets.enabled = true
48 | end
49 | end
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll automatically include all the stylesheets available in this directory
3 | * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
4 | * the top of the compiled file, but it's generally better to create a new file per style scope.
5 | *= require_self
6 | *= require_tree .
7 | */
8 |
9 | body {
10 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
11 | color: #252519;
12 | font-size: 15px;
13 | margin: 0;
14 | -webkit-font-smoothing: antialiased;
15 | background: #D0D0D0;
16 | }
17 |
18 | a, a:visited {
19 | color: #261a3b;
20 | text-decoration: underline;
21 | cursor: pointer;
22 | }
23 |
24 | hr {
25 | border: 0;
26 | height: 1px;
27 | background-color: #E2E2E2;
28 | margin: 1em 1em 1.5em;
29 | }
30 |
31 | abbr {
32 | cursor: help;
33 | border-bottom: 1px dashed #000;
34 | }
35 |
36 | p {
37 | margin: 15px 0;
38 | line-height: 1.7em;
39 | }
40 |
41 | h1, h2, h3, h4, h5, h6 {
42 | margin: 15px 0 15px 0;
43 | }
44 |
45 | h2 {
46 | font-size: 1.2em;
47 | }
48 |
49 | h1 {
50 | padding: 10px 0 8px 0;
51 | margin-top: 30px;
52 | border-bottom: 1px solid #e5e5ee;
53 | }
54 |
55 | h1 a {
56 | text-decoration: none;
57 | }
58 |
59 | pre, code {
60 | font-size: 12px; line-height: 18px;
61 | font-family: Monaco, Consolas, "Lucida Console", monospace;
62 | margin: 0; padding: 0;
63 | }
64 |
65 | pre {
66 | overflow: auto;
67 | border: 1px solid #e5e5ee;
68 | margin: 0 0 15px 0;
69 | background: ghostWhite;
70 | padding: 5px;
71 | }
72 |
73 | ul {
74 | padding: 0;
75 | margin: 10px 0;
76 | list-style-position: inside;
77 | }
78 |
79 | ul li {
80 | line-height: 1.3em;
81 | }
82 |
83 | label, label span {
84 | display: block;
85 | }
86 |
87 | label {
88 | margin: 10px 0;
89 | }
90 |
91 | label span {
92 | margin: 0 0 5px 0;
93 | }
94 |
95 | input[type=text], textarea {
96 | padding: 3px;
97 | margin: 0;
98 | border: 1px solid rgba(0, 0, 0, 0.25);
99 |
100 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);
101 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);
102 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);
103 | }
104 |
105 | input[type=text]:focus, textarea:focus, select:focus {
106 | outline: none;
107 | border-color: rgba(104, 189, 244, 0.8);
108 |
109 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(104, 189, 244, 0.6);
110 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(104, 189, 244, 0.6);
111 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(104, 189, 244, 0.6);
112 | }
113 |
114 | textarea {
115 | padding: 5px;
116 | height: 80px;
117 | }
118 |
119 | input[type=text], textarea {
120 | min-width: 200px;
121 | }
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: http://rubygems.org/
3 | specs:
4 | actionmailer (3.1.0)
5 | actionpack (= 3.1.0)
6 | mail (~> 2.3.0)
7 | actionpack (3.1.0)
8 | activemodel (= 3.1.0)
9 | activesupport (= 3.1.0)
10 | builder (~> 3.0.0)
11 | erubis (~> 2.7.0)
12 | i18n (~> 0.6)
13 | rack (~> 1.3.2)
14 | rack-cache (~> 1.0.3)
15 | rack-mount (~> 0.8.2)
16 | rack-test (~> 0.6.1)
17 | sprockets (~> 2.0.0)
18 | activemodel (3.1.0)
19 | activesupport (= 3.1.0)
20 | bcrypt-ruby (~> 3.0.0)
21 | builder (~> 3.0.0)
22 | i18n (~> 0.6)
23 | activerecord (3.1.0)
24 | activemodel (= 3.1.0)
25 | activesupport (= 3.1.0)
26 | arel (~> 2.2.1)
27 | tzinfo (~> 0.3.29)
28 | activeresource (3.1.0)
29 | activemodel (= 3.1.0)
30 | activesupport (= 3.1.0)
31 | activesupport (3.1.0)
32 | multi_json (~> 1.0)
33 | archive-tar-minitar (0.5.2)
34 | arel (2.2.1)
35 | bcrypt-ruby (3.0.1)
36 | builder (3.0.0)
37 | coffee-rails (3.1.1)
38 | coffee-script (>= 2.2.0)
39 | railties (~> 3.1.0)
40 | coffee-script (2.2.0)
41 | coffee-script-source
42 | execjs
43 | coffee-script-source (1.1.2)
44 | columnize (0.3.4)
45 | daemons (1.1.4)
46 | eco (1.0.0)
47 | coffee-script
48 | eco-source
49 | execjs
50 | eco-source (1.1.0.rc.1)
51 | erubis (2.7.0)
52 | eventmachine (0.12.10)
53 | execjs (1.2.9)
54 | multi_json (~> 1.0)
55 | hike (1.2.1)
56 | i18n (0.6.0)
57 | jquery-rails (1.0.16)
58 | railties (~> 3.0)
59 | thor (~> 0.14)
60 | json (1.6.1)
61 | linecache19 (0.5.12)
62 | ruby_core_source (>= 0.1.4)
63 | mail (2.3.0)
64 | i18n (>= 0.4.0)
65 | mime-types (~> 1.16)
66 | treetop (~> 1.4.8)
67 | mime-types (1.16)
68 | multi_json (1.0.3)
69 | pg (0.11.0)
70 | polyglot (0.3.2)
71 | rack (1.3.4)
72 | rack-cache (1.0.3)
73 | rack (>= 0.4)
74 | rack-mount (0.8.3)
75 | rack (>= 1.0.0)
76 | rack-ssl (1.3.2)
77 | rack
78 | rack-test (0.6.1)
79 | rack (>= 1.0)
80 | rails (3.1.0)
81 | actionmailer (= 3.1.0)
82 | actionpack (= 3.1.0)
83 | activerecord (= 3.1.0)
84 | activeresource (= 3.1.0)
85 | activesupport (= 3.1.0)
86 | bundler (~> 1.0)
87 | railties (= 3.1.0)
88 | railties (3.1.0)
89 | actionpack (= 3.1.0)
90 | activesupport (= 3.1.0)
91 | rack-ssl (~> 1.3.2)
92 | rake (>= 0.8.7)
93 | rdoc (~> 3.4)
94 | thor (~> 0.14.6)
95 | rake (0.9.2)
96 | rdoc (3.10)
97 | json (~> 1.4)
98 | ruby-debug-base19 (0.11.25)
99 | columnize (>= 0.3.1)
100 | linecache19 (>= 0.5.11)
101 | ruby_core_source (>= 0.1.4)
102 | ruby-debug19 (0.11.6)
103 | columnize (>= 0.3.1)
104 | linecache19 (>= 0.5.11)
105 | ruby-debug-base19 (>= 0.11.19)
106 | ruby_core_source (0.1.5)
107 | archive-tar-minitar (>= 0.5.2)
108 | sass (3.1.10)
109 | spine-rails (0.0.4)
110 | actionpack (~> 3.1.0)
111 | sprockets (2.0.3)
112 | hike (~> 1.2)
113 | rack (~> 1.0)
114 | tilt (~> 1.1, != 1.3.0)
115 | sqlite3 (1.3.4)
116 | thin (1.2.11)
117 | daemons (>= 1.0.9)
118 | eventmachine (>= 0.12.6)
119 | rack (>= 1.0.0)
120 | thor (0.14.6)
121 | tilt (1.3.3)
122 | treetop (1.4.10)
123 | polyglot
124 | polyglot (>= 0.3.1)
125 | tzinfo (0.3.30)
126 | uglifier (1.0.3)
127 | execjs (>= 0.3.0)
128 | multi_json (>= 1.0.2)
129 |
130 | PLATFORMS
131 | ruby
132 |
133 | DEPENDENCIES
134 | coffee-rails
135 | eco
136 | jquery-rails
137 | pg
138 | rails (= 3.1.0)
139 | ruby-debug19
140 | sass
141 | spine-rails
142 | sqlite3
143 | thin
144 | uglifier
145 |
--------------------------------------------------------------------------------
/app/assets/javascripts/app/lib/jquery.waypoints.js:
--------------------------------------------------------------------------------
1 | /*!
2 | jQuery Waypoints - v1.1.2
3 | Copyright (c) 2011 Caleb Troughton
4 | Dual licensed under the MIT license and GPL license.
5 | https://github.com/imakewebthings/jquery-waypoints/blob/master/MIT-license.txt
6 | https://github.com/imakewebthings/jquery-waypoints/blob/master/GPL-license.txt
7 | */
8 |
9 | /*
10 | Waypoints is a small jQuery plugin that makes it easy to execute a function
11 | whenever you scroll to an element.
12 |
13 | GitHub Repository: https://github.com/imakewebthings/jquery-waypoints
14 | Documentation and Examples: http://imakewebthings.github.com/jquery-waypoints
15 |
16 | Changelog:
17 | v1.1.2
18 | - Fixed error thrown by waypoints with triggerOnce option that were
19 | triggered via resize refresh.
20 | v1.1.1
21 | - Fixed bug in initialization where all offsets were being calculated
22 | as if set to 0 initially, causing unwarranted triggers during the
23 | subsequent refresh.
24 | - Added onlyOnScroll, an option for individual waypoints that disables
25 | triggers due to an offset refresh that crosses the current scroll
26 | point. (All credit to @knuton on this one.)
27 | v1.1
28 | - Moved the continuous option out of global settings and into the options
29 | object for individual waypoints.
30 | - Added the context option, which allows for using waypoints within any
31 | scrollable element, not just the window.
32 | v1.0.2
33 | - Moved scroll and resize handler bindings out of load. Should play nicer
34 | with async loaders like Head JS and LABjs.
35 | - Fixed a 1px off error when using certain % offsets.
36 | - Added unit tests.
37 | v1.0.1
38 | - Added $.waypoints('viewportHeight').
39 | - Fixed iOS bug (using the new viewportHeight method).
40 | - Added offset function alias: 'bottom-in-view'.
41 | v1.0
42 | - Initial release.
43 |
44 | Support:
45 | - jQuery versions 1.4.3+
46 | - IE6+, FF3+, Chrome 6+, Safari 4+, Opera 11
47 | - Other versions and browsers may work, these are just the ones I've looked at.
48 | */
49 |
50 | (function($, wp, wps, window, undefined){
51 | '$:nomunge';
52 |
53 | var $w = $(window),
54 |
55 | // Keeping common strings as variables = better minification
56 | eventName = 'waypoint.reached',
57 |
58 | /*
59 | For the waypoint and direction passed in, trigger the waypoint.reached
60 | event and deal with the triggerOnce option.
61 | */
62 | triggerWaypoint = function(way, dir) {
63 | way.element.trigger(eventName, dir);
64 | if (way.options.triggerOnce) {
65 | way.element[wp]('destroy');
66 | }
67 | },
68 |
69 | /*
70 | Given a jQuery element and Context, returns the index of that element in the waypoints
71 | array. Returns the index, or -1 if the element is not a waypoint.
72 | */
73 | waypointIndex = function(el, context) {
74 | var i = context.waypoints.length - 1;
75 | while (i >= 0 && context.waypoints[i].element[0] !== el[0]) {
76 | i -= 1;
77 | }
78 | return i;
79 | },
80 |
81 | // Private list of all elements used as scrolling contexts for waypoints.
82 | contexts = [],
83 |
84 | /*
85 | Context Class - represents a scrolling context. Properties include:
86 | element: jQuery object containing a single HTML element.
87 | waypoints: Array of waypoints operating under this scroll context.
88 | oldScroll: Keeps the previous scroll position to determine scroll direction.
89 | didScroll: Flag used in scrolling the context's scroll event.
90 | didResize: Flag used in scrolling the context's resize event.
91 | doScroll: Function that checks for crossed waypoints. Called from throttler.
92 | */
93 | Context = function(context) {
94 | $.extend(this, {
95 | 'element': $(context),
96 |
97 | /*
98 | Starting at a ridiculous negative number allows for a 'down' trigger of 0 or
99 | negative offset waypoints on load. Useful for setting initial states.
100 | */
101 | 'oldScroll': -99999,
102 |
103 | /*
104 | List of all elements that have been registered as waypoints.
105 | Each object in the array contains:
106 | element: jQuery object containing a single HTML element.
107 | offset: The window scroll offset, in px, that triggers the waypoint event.
108 | options: Options object that was passed to the waypoint fn function.
109 | */
110 | 'waypoints': [],
111 |
112 | didScroll: false,
113 | didResize: false,
114 |
115 | doScroll: $.proxy(function() {
116 | var newScroll = this.element.scrollTop(),
117 |
118 | // Are we scrolling up or down? Used for direction argument in callback.
119 | isDown = newScroll > this.oldScroll,
120 | that = this,
121 |
122 | // Get a list of all waypoints that were crossed since last scroll move.
123 | pointsHit = $.grep(this.waypoints, function(el, i) {
124 | return isDown ?
125 | (el.offset > that.oldScroll && el.offset <= newScroll) :
126 | (el.offset <= that.oldScroll && el.offset > newScroll);
127 | }),
128 | len = pointsHit.length;
129 |
130 | // iOS adjustment
131 | if (!this.oldScroll || !newScroll) {
132 | $[wps]('refresh');
133 | }
134 |
135 | // Done with scroll comparisons, store new scroll before ejection
136 | this.oldScroll = newScroll;
137 |
138 | // No waypoints crossed? Eject.
139 | if (!len) return;
140 |
141 | // If several waypoints triggered, need to do so in reverse order going up
142 | if (!isDown) pointsHit.reverse();
143 |
144 | /*
145 | One scroll move may cross several waypoints. If the waypoint's continuous
146 | option is true it should fire even if it isn't the last waypoint. If false,
147 | it will only fire if it's the last one.
148 | */
149 | $.each(pointsHit, function(i, point) {
150 | if (point.options.continuous || i === len - 1) {
151 | triggerWaypoint(point, [isDown ? 'down' : 'up']);
152 | }
153 | });
154 | }, this)
155 | });
156 |
157 | // Setup scroll and resize handlers. Throttled at the settings-defined rate limits.
158 | $(context).scroll($.proxy(function() {
159 | if (!this.didScroll) {
160 | this.didScroll = true;
161 | window.setTimeout($.proxy(function() {
162 | this.doScroll();
163 | this.didScroll = false;
164 | }, this), $[wps].settings.scrollThrottle);
165 | }
166 | }, this)).resize($.proxy(function() {
167 | if (!this.didResize) {
168 | this.didResize = true;
169 | window.setTimeout($.proxy(function() {
170 | $[wps]('refresh');
171 | this.didResize = false;
172 | }, this), $[wps].settings.resizeThrottle);
173 | }
174 | }, this));
175 |
176 | $w.load($.proxy(function() {
177 | /*
178 | Fire a scroll check, should the page be loaded at a non-zero scroll value,
179 | as with a fragment id link or a page refresh.
180 | */
181 | this.doScroll();
182 | }, this));
183 | },
184 |
185 | /* Returns a Context object from the contexts array, given the raw HTML element
186 | for that context. */
187 | getContextByElement = function(element) {
188 | var found = null;
189 |
190 | $.each(contexts, function(i, c) {
191 | if (c.element[0] === element) {
192 | found = c;
193 | return false;
194 | }
195 | });
196 |
197 | return found;
198 | },
199 |
200 | // Methods exposed to the effin' object
201 | methods = {
202 | /*
203 | jQuery.fn.waypoint([handler], [options])
204 |
205 | handler
206 | function, optional
207 | A callback function called when the user scrolls past the element.
208 | The function signature is function(event, direction) where event is
209 | a standard jQuery Event Object and direction is a string, either 'down'
210 | or 'up' indicating which direction the user is scrolling.
211 |
212 | options
213 | object, optional
214 | A map of options to apply to this set of waypoints, including where on
215 | the browser window the waypoint is triggered. For a full list of
216 | options and their defaults, see $.fn.waypoint.defaults.
217 |
218 | This is how you register an element as a waypoint. When the user scrolls past
219 | that element it triggers waypoint.reached, a custom event. Since the
220 | parameters for creating a waypoint are optional, we have a few different
221 | possible signatures. Let’s look at each of them.
222 |
223 | someElements.waypoint();
224 |
225 | Calling .waypoint with no parameters will register the elements as waypoints
226 | using the default options. The elements will fire the waypoint.reached event,
227 | but calling it in this way does not bind any handler to the event. You can
228 | bind to the event yourself, as with any other event, like so:
229 |
230 | someElements.bind('waypoint.reached', function(event, direction) {
231 | // make it rain
232 | });
233 |
234 | You will usually want to create a waypoint and immediately bind a function to
235 | waypoint.reached, and can do so by passing a handler as the first argument to
236 | .waypoint:
237 |
238 | someElements.waypoint(function(event, direction) {
239 | if (direction === 'down') {
240 | // do this on the way down
241 | }
242 | else {
243 | // do this on the way back up through the waypoint
244 | }
245 | });
246 |
247 | This will still use the default options, which will trigger the waypoint when
248 | the top of the element hits the top of the window. We can pass .waypoint an
249 | options object to customize things:
250 |
251 | someElements.waypoint(function(event, direction) {
252 | // do something amazing
253 | }, {
254 | offset: '50%' // middle of the page
255 | });
256 |
257 | You can also pass just an options object.
258 |
259 | someElements.waypoint({
260 | offset: 100 // 100px from the top
261 | });
262 |
263 | This behaves like .waypoint(), in that it registers the elements as waypoints
264 | but binds no event handlers.
265 |
266 | Calling .waypoint on an existing waypoint will extend the previous options.
267 | If the call includes a handler, it will be bound to waypoint.reached without
268 | unbinding any other handlers.
269 | */
270 | init: function(f, options) {
271 | // Register each element as a waypoint, add to array.
272 | this.each(function() {
273 | var cElement = $.fn[wp].defaults.context,
274 | context,
275 | $this = $(this);
276 |
277 | // Default window context or a specific element?
278 | if (options && options.context) {
279 | cElement = options.context;
280 | }
281 |
282 | // Find the closest element that matches the context
283 | if (!$.isWindow(cElement)) {
284 | cElement = $this.closest(cElement)[0];
285 | }
286 | context = getContextByElement(cElement);
287 |
288 | // Not a context yet? Create and push.
289 | if (!context) {
290 | context = new Context(cElement);
291 | contexts.push(context);
292 | }
293 |
294 | // Extend default and preexisting options
295 | var ndx = waypointIndex($this, context),
296 | base = ndx < 0 ? $.fn[wp].defaults : context.waypoints[ndx].options,
297 | opts = $.extend({}, base, options);
298 |
299 | // Offset aliases
300 | opts.offset = opts.offset === "bottom-in-view" ?
301 | function() {
302 | var cHeight = $.isWindow(cElement) ? $[wps]('viewportHeight')
303 | : $(cElement).height();
304 | return cHeight - $(this).outerHeight();
305 | } : opts.offset;
306 |
307 | // Update, or create new waypoint
308 | if (ndx < 0) {
309 | context.waypoints.push({
310 | 'element': $this,
311 | 'offset': null,
312 | 'options': opts
313 | });
314 | }
315 | else {
316 | context.waypoints[ndx].options = opts;
317 | }
318 |
319 | // Bind the function if it was passed in.
320 | if (f) {
321 | $this.bind(eventName, f);
322 | }
323 | });
324 |
325 | // Need to re-sort+refresh the waypoints array after new elements are added.
326 | $[wps]('refresh');
327 |
328 | return this;
329 | },
330 |
331 |
332 | /*
333 | jQuery.fn.waypoint('remove')
334 |
335 | Passing the string 'remove' to .waypoint unregisters the elements as waypoints
336 | and wipes any custom options, but leaves the waypoint.reached events bound.
337 | Calling .waypoint again in the future would reregister the waypoint and the old
338 | handlers would continue to work.
339 | */
340 | remove: function() {
341 | return this.each(function(i, el) {
342 | var $el = $(el);
343 |
344 | $.each(contexts, function(i, c) {
345 | var ndx = waypointIndex($el, c);
346 |
347 | if (ndx >= 0) {
348 | c.waypoints.splice(ndx, 1);
349 | }
350 | });
351 | });
352 | },
353 |
354 | /*
355 | jQuery.fn.waypoint('destroy')
356 |
357 | Passing the string 'destroy' to .waypoint will unbind all waypoint.reached
358 | event handlers on those elements and unregisters them as waypoints.
359 | */
360 | destroy: function() {
361 | return this.unbind(eventName)[wp]('remove');
362 | }
363 | },
364 |
365 | /*
366 | Methods used by the jQuery object extension.
367 | */
368 | jQMethods = {
369 |
370 | /*
371 | jQuery.waypoints('refresh')
372 |
373 | This will force a recalculation of each waypoint’s trigger point based on
374 | its offset option and context. This is called automatically whenever the window
375 | (or other defined context) is resized, new waypoints are added, or a waypoint’s
376 | options are modified. If your project is changing the DOM or page layout without
377 | doing one of these things, you may want to manually call this refresh.
378 | */
379 | refresh: function() {
380 | $.each(contexts, function(i, c) {
381 | var isWin = $.isWindow(c.element[0]),
382 | contextOffset = isWin ? 0 : c.element.offset().top,
383 | contextHeight = isWin ? $[wps]('viewportHeight') : c.element.height(),
384 | contextScroll = isWin ? 0 : c.element.scrollTop();
385 |
386 | $.each(c.waypoints, function(j, o) {
387 | /* $.each isn't safe from element removal due to triggerOnce.
388 | Should rewrite the loop but this is way easier. */
389 | if (!o) return;
390 |
391 | // Adjustment is just the offset if it's a px value
392 | var adjustment = o.options.offset,
393 | oldOffset = o.offset;
394 |
395 | // Set adjustment to the return value if offset is a function.
396 | if (typeof o.options.offset === "function") {
397 | adjustment = o.options.offset.apply(o.element);
398 | }
399 | // Calculate the adjustment if offset is a percentage.
400 | else if (typeof o.options.offset === "string") {
401 | var amount = parseFloat(o.options.offset);
402 | adjustment = o.options.offset.indexOf("%") ?
403 | Math.ceil(contextHeight * (amount / 100)) : amount;
404 | }
405 |
406 | /*
407 | Set the element offset to the window scroll offset, less
408 | all our adjustments.
409 | */
410 | o.offset = o.element.offset().top - contextOffset
411 | + contextScroll - adjustment;
412 |
413 | /*
414 | An element offset change across the current scroll point triggers
415 | the event, just as if we scrolled past it unless prevented by an
416 | optional flag.
417 | */
418 | if (o.options.onlyOnScroll) return;
419 |
420 | if (oldOffset !== null && c.oldScroll > oldOffset && c.oldScroll <= o.offset) {
421 | triggerWaypoint(o, ['up']);
422 | }
423 | else if (oldOffset !== null && c.oldScroll < oldOffset && c.oldScroll >= o.offset) {
424 | triggerWaypoint(o, ['down']);
425 | }
426 | });
427 |
428 | // Keep waypoints sorted by offset value.
429 | c.waypoints.sort(function(a, b) {
430 | return a.offset - b.offset;
431 | });
432 | });
433 | },
434 |
435 |
436 | /*
437 | jQuery.waypoints('viewportHeight')
438 |
439 | This will return the height of the viewport, adjusting for inconsistencies
440 | that come with calling $(window).height() in iOS. Recommended for use
441 | within any offset functions.
442 | */
443 | viewportHeight: function() {
444 | return (window.innerHeight ? window.innerHeight : $w.height());
445 | },
446 |
447 |
448 | /*
449 | jQuery.waypoints()
450 |
451 | This will return a jQuery object with a collection of all registered waypoint
452 | elements.
453 |
454 | $('.post').waypoint();
455 | $('.ad-unit').waypoint(function(event, direction) {
456 | // Passed an ad unit
457 | });
458 | console.log($.waypoints());
459 |
460 | The example above would log a jQuery object containing all .post and .ad-unit
461 | elements.
462 | */
463 | aggregate: function() {
464 | var points = $();
465 | $.each(contexts, function(i, c) {
466 | $.each(c.waypoints, function(i, e) {
467 | points = points.add(e.element);
468 | });
469 | });
470 | return points;
471 | }
472 | };
473 |
474 |
475 | /*
476 | fn extension. Delegates to appropriate method.
477 | */
478 | $.fn[wp] = function(method) {
479 |
480 | if (methods[method]) {
481 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
482 | }
483 | else if (typeof method === "function" || !method) {
484 | return methods.init.apply(this, arguments);
485 | }
486 | else if (typeof method === "object") {
487 | return methods.init.apply(this, [null, method]);
488 | }
489 | else {
490 | $.error( 'Method ' + method + ' does not exist on jQuery ' + wp );
491 | }
492 | };
493 |
494 |
495 | /*
496 | The default options object that is extended when calling .waypoint. It has the
497 | following properties:
498 |
499 | context
500 | string | element | jQuery*
501 | default: window
502 | The context defines which scrollable element the waypoint belongs to and acts
503 | within. The default, window, means the waypoint offset is calculated with relation
504 | to the whole viewport. You can set this to another element to use the waypoints
505 | within that element. Accepts a selector string, *but if you use jQuery 1.6+ it
506 | also accepts a raw HTML element or jQuery object.
507 |
508 | continuous
509 | boolean
510 | default: true
511 | If true, and multiple waypoints are triggered in one scroll, this waypoint will
512 | trigger even if it is not the last waypoint reached. If false, it will only
513 | trigger if it is the last waypoint.
514 |
515 | offset
516 | number | string | function
517 | default: 0
518 | Determines how far the top of the element must be from the top of the browser
519 | window to trigger a waypoint. It can be a number, which is taken as a number
520 | of pixels, a string representing a percentage of the viewport height, or a
521 | function that will return a number of pixels.
522 |
523 | onlyOnScroll
524 | boolean
525 | default: false
526 | If true, this waypoint will not trigger if an offset change during a refresh
527 | causes it to pass the current scroll point.
528 |
529 | triggerOnce
530 | boolean
531 | default: false
532 | If true, the waypoint will be destroyed when triggered.
533 |
534 | An offset of 250 would trigger the waypoint when the top of the element is 250px
535 | from the top of the viewport. Negative values for any offset work as you might
536 | expect. A value of -100 would trigger the waypoint when the element is 100px above
537 | the top of the window.
538 |
539 | offset: '100%'
540 |
541 | A string percentage will determine the pixel offset based on the height of the
542 | window. When resizing the window, this offset will automatically be recalculated
543 | without needing to call $.waypoints('refresh').
544 |
545 | // The bottom of the element is in view
546 | offset: function() {
547 | return $.waypoints('viewportHeight') - $(this).outerHeight();
548 | }
549 |
550 | Offset can take a function, which must return a number of pixels from the top of
551 | the window. The this value will always refer to the raw HTML element of the
552 | waypoint. As with % values, functions are recalculated automatically when the
553 | window resizes. For more on recalculating offsets, see $.waypoints('refresh').
554 |
555 | An offset value of 'bottom-in-view' will act as an alias for the function in the
556 | example above, as this is a common usage.
557 |
558 | offset: 'bottom-in-view'
559 |
560 | You can see this alias in use on the Scroll Analytics example page.
561 |
562 | The triggerOnce flag, if true, will destroy the waypoint after the first trigger.
563 | This is just a shortcut for calling .waypoint('destroy') within the waypoint
564 | handler. This is useful in situations such as scroll analytics, where you only
565 | want to record an event once for each page visit.
566 |
567 | The context option lets you use Waypoints within an element other than the window.
568 | You can define the context with a selector string and the waypoint will act within
569 | the nearest ancestor that matches this selector.
570 |
571 | $('.something-scrollable .waypoint').waypoint({
572 | context: '.something-scrollable'
573 | });
574 |
575 | You can see this in action on the Dial Controls example.
576 | */
577 | $.fn[wp].defaults = {
578 | continuous: true,
579 | offset: 0,
580 | triggerOnce: false,
581 | context: window
582 | };
583 |
584 |
585 |
586 |
587 |
588 | /*
589 | jQuery object extension. Delegates to appropriate methods above.
590 | */
591 | $[wps] = function(method) {
592 | if (jQMethods[method]) {
593 | return jQMethods[method].apply(this);
594 | }
595 | else {
596 | return jQMethods['aggregate']();
597 | }
598 | };
599 |
600 |
601 | /*
602 | $.waypoints.settings
603 |
604 | Settings object that determines some of the plugin’s behavior.
605 |
606 | resizeThrottle
607 | number
608 | default: 200
609 | For performance reasons, the refresh performed during resizes is
610 | throttled. This value is the rate-limit in milliseconds between resize
611 | refreshes. For more information on throttling, check out Ben Alman’s
612 | throttle / debounce plugin.
613 | http://benalman.com/projects/jquery-throttle-debounce-plugin/
614 |
615 | scrollThrottle
616 | number
617 | default: 100
618 | For performance reasons, checking for any crossed waypoints during a
619 | scroll event is throttled. This value is the rate-limit in milliseconds
620 | between scroll checks. For more information on throttling, check out Ben
621 | Alman’s throttle / debounce plugin.
622 | http://benalman.com/projects/jquery-throttle-debounce-plugin/
623 | */
624 | $[wps].settings = {
625 | resizeThrottle: 200,
626 | scrollThrottle: 100
627 | };
628 |
629 | $w.load(function() {
630 | // Calculate everything once on load.
631 | $[wps]('refresh');
632 | });
633 | })(jQuery, 'waypoint', 'waypoints', this);
634 |
--------------------------------------------------------------------------------