2015-04-24 11:21:13 -04:00
**Important**
- `master` branch contains the bleeding edge development code.
- check `branches` or `tags` for the latest stable release or specific versions.
2013-10-12 08:48:18 -04:00
# Paloma
2015-04-24 11:08:20 -04:00
Page-specific javascript for Rails done right.
2013-10-12 22:08:49 -04:00
2013-10-12 08:48:18 -04:00
## Advantages
* Choose what specific javascript code to run per page.
2013-01-25 22:08:50 -05:00
* Easily make ruby variables available on your javascript files.
2016-03-25 05:15:20 -04:00
* Write in vanilla javascript, coffeescript, and anything that compiles to js.
* No external JS library dependency.
* Easy to understand (*because it is patterned after Rails controller*).
2013-10-12 08:55:14 -04:00
2016-03-25 04:30:46 -04:00
## Minimum Requirement
* Rails 3.1 or higher
2013-10-12 08:48:18 -04:00
## Quick Example
2012-12-19 02:56:52 -05:00
2016-03-25 04:30:46 -04:00
Paloma controller:
2012-12-19 02:56:52 -05:00
```javascript
2016-03-06 22:17:59 -05:00
Paloma.controller('Users', {
new: function(){
2016-03-25 04:30:46 -04:00
// Executes when Rails Users#new is executed.
2016-03-06 22:17:59 -05:00
alert('Hello Sexy User!');
}
});
2012-12-19 02:56:52 -05:00
```
2016-03-25 04:30:46 -04:00
Rails controller:
2012-12-19 02:56:52 -05:00
```ruby
def UsersController < ApplicationController
2016-03-25 04:30:46 -04:00
def new
# no special method to call
@user = User.new
end
2012-12-19 02:56:52 -05:00
end
```
2012-12-18 04:47:24 -05:00
2013-10-12 08:55:14 -04:00
## Install
2016-03-01 22:52:54 -05:00
1. Install gem.
- Without bundler: `sudo gem install paloma` .
2016-03-25 05:15:20 -04:00
- With bundler, add this to your Gemfile:
```ruby
gem 'paloma', '~> 5.0.0'
```
2016-03-01 22:52:54 -05:00
2016-03-25 04:30:46 -04:00
1. Require `paloma` in your `application.js` :
```
//= require paloma
```
2016-03-01 22:52:54 -05:00
2016-03-25 05:15:20 -04:00
1. In your layouts, insert Paloma's hook. This is responsible for connecting your ruby code to your javascript code.
2015-04-25 05:30:33 -04:00
`application.html.erb`
```html
< html >
< head >
< / head >
2016-03-25 04:30:46 -04:00
2015-04-25 05:30:33 -04:00
< body >
< %= yield %>
< %= insert_paloma_hook %>
< / body >
< / html >
```
2013-10-12 09:12:10 -04:00
2016-03-25 05:15:20 -04:00
1. Start Paloma to initialize the appropriate controller and execute a certain action. Most of the time this will be inside `document.ready` .
2016-03-25 04:30:46 -04:00
2016-03-01 22:52:54 -05:00
```js
$(document).ready(function(){
Paloma.start();
});
```
2016-03-25 04:30:46 -04:00
### Controller
2013-10-12 09:24:40 -04:00
2016-03-25 05:15:20 -04:00
Paloma controllers are javascript classes which will be mapped with your Rails controller. Basically, both Paloma and Rails controllers will share the same name.
2013-10-12 09:24:40 -04:00
2016-03-25 04:30:46 -04:00
It is created or accessed (if existing), using `Paloma.controller` method.
2013-10-12 09:24:40 -04:00
2016-03-25 04:30:46 -04:00
```js
2013-10-13 06:25:12 -04:00
var ArticlesController = Paloma.controller('Articles');
2016-03-25 04:30:46 -04:00
```
2013-10-12 09:24:40 -04:00
2016-03-25 05:15:20 -04:00
Note: Using `Paloma.controller` method, you can access the same controller across different files.
2014-02-15 06:25:44 -05:00
2016-03-25 04:30:46 -04:00
### Actions
2013-10-12 09:24:40 -04:00
2016-03-25 05:15:20 -04:00
To handle specific actions of your Rails controller, add methods to your Paloma controller's prototype.
2013-10-12 09:24:40 -04:00
2016-03-25 04:30:46 -04:00
```js
var ArticlesController = Paloma.controller('Articles');
2016-03-07 00:18:49 -05:00
2016-03-25 04:30:46 -04:00
ArticlesController.prototype.edit = function(){
2016-03-07 00:18:49 -05:00
// Handle edit article
};
```
2016-03-07 00:36:59 -05:00
2016-03-25 05:15:20 -04:00
Or you can pass the prototype value as the 2nd argument of the `Paloma.controller` method.
2016-03-07 00:18:49 -05:00
```js
2016-03-06 22:17:59 -05:00
Paloma.controller('Articles', {
edit: function(){
2016-03-07 00:18:49 -05:00
// Handle edit article
2016-03-06 22:17:59 -05:00
}
});
2013-10-12 09:24:40 -04:00
```
2013-10-12 09:05:06 -04:00
2016-03-07 00:27:30 -05:00
### Namespace
2016-03-25 05:15:20 -04:00
Namespaced controller should follow the format `namespace/controller` .
2016-03-07 00:27:30 -05:00
Rails controller:
```ruby
class Admin::UsersController < ApplicationController
def new
@user = User.new
end
end
```
Paloma controller:
```js
Paloma.controller('Admin/Users', {
new: function(){
// Handle new admin user
}
});
```
### Controller Inheritance
2016-03-25 05:15:20 -04:00
Controller inheritance is accomplished using the syntax `Controller < ParentController` *(same as ruby's syntax)* .
2016-03-25 04:30:46 -04:00
Parent:
2016-03-07 00:27:30 -05:00
```js
Paloma.controller('Application', {
index: function(){
alert('Application: Index');
},
2016-03-25 04:30:46 -04:00
2016-03-07 00:27:30 -05:00
new: function(){
alert('Application: New');
}
});
2016-03-25 04:30:46 -04:00
```
Child:
```js
2016-03-07 00:27:30 -05:00
Paloma.controller('Users < Application ' , {
// Override Application's new action
new: function(){
alert('Users: New');
}
});
```
2016-03-25 05:15:20 -04:00
## Before Callbacks
Executing a method before doing an action can be done using the `before` property of a controller.
```js
Paloma.controller('Articles', {
before: ['show -> alert'],
show: function(){
// Handle show Article
},
alert: function(){
alert("You are about to show an article.");
}
});
```
Multiple actions and callbacks should be separated by spaces.
The callbacks order on the string will define the order of their execution.
So in this case, `alert` will be executed first before `log` .
```js
Paloma.controller('Articles', {
before: ['show index -> alert log'],
index: function(){},
show: function(){},
alert: function(){
alert('Before index and show');
},
log: function(){
console.log('Before index and show');
}
});
```
### Multiple Before Entries
The order of execution is also based on the order of entries on the `before` array.
```js
Paloma.controller('Articles', {
before: [
'show -> beforeShow',
'index -> beforeIndex',
'show index -> beforeShowAndIndex'
],
beforeShow: function(){ alert('Before Show'); },
beforeShowAndIndex: function(){ alert('Before Show and Index'); }
});
```
When `show` is executed, the following callbacks will be called in this order: `beforeShow` then `beforeShowAndIndex` .
### Before All Actions
`all` is a special string that can be used to indicate a catch-all callback.
```js
Paloma.controller('Articles', {
before: ['all -> initialize'],
initialize: function(){
alert('execute before every action');
}
});
```
## Execution Details
You can access what `controller` and `action` Paloma is about to execute or already executed,
by accessing the `controller` and `action` property of a Paloma controller.
```js
Paloma.controller('Users', {
before: ['all -> log'],
log: function(){
console.log('Controller: ' + this.controller);
console.log('Action: ' + this.action);
}
})
```
2014-02-15 06:34:15 -05:00
## Advanced Usage
2014-02-15 07:08:17 -05:00
You can manipulate what controller/action should Paloma execute by calling `js` method **before** rendering.
2014-02-15 06:34:15 -05:00
2016-03-25 04:30:46 -04:00
1. Changing controller.
2014-02-15 07:08:17 -05:00
2016-03-25 04:30:46 -04:00
```ruby
class UsersController < ApplicationController
def new
@user = User.new
# will use Accounts controller instead of Users controller
js 'Accounts'
end
end
```
2014-02-15 06:34:15 -05:00
2016-03-25 04:30:46 -04:00
2. Changing action.
2014-02-15 07:08:17 -05:00
2016-03-25 04:30:46 -04:00
You can use the symbol syntax:
```ruby
def new
@user = User.new
# will execute register method instead of new
js :register
end
```
Or the string syntax:
```ruby
def new
@user = User.new
# will execute register method instead of new
js '#register'
end
```
2014-02-15 06:34:15 -05:00
2014-02-15 07:08:17 -05:00
3. Changing controller and action.
2016-03-25 04:30:46 -04:00
```ruby
def new
@user = User.new
2014-02-15 06:34:15 -05:00
2016-03-25 04:30:46 -04:00
# will execute Accounts#register instead of Users#new
js 'Accounts#register'
end
```
2014-02-15 07:08:17 -05:00
2016-03-25 05:15:20 -04:00
4. Changing controller and action with namespace.
2016-03-25 04:30:46 -04:00
```ruby
def new
@user = User.new
# will use Admin/Accounts instead of Users controller
js `Admin/Accounts`
end
```
```ruby
def new
@user = User.new
# will execute Admin/Accounts#register instead of Users#new
js 'Admin/Accounts#register'
end
```
2014-02-15 06:34:15 -05:00
2014-02-15 07:08:17 -05:00
## Passing Parameters
2016-03-07 00:36:59 -05:00
You can pass parameters to your Paloma Controller in two ways.
2014-02-15 07:08:17 -05:00
2016-03-07 00:36:59 -05:00
1. Passing a hash. (*parameters only*)
2016-03-25 04:30:46 -04:00
2016-03-07 00:36:59 -05:00
```ruby
def show
user = User.find params[:id]
2016-03-25 04:30:46 -04:00
2016-03-25 05:15:20 -04:00
js :id => user.id, :myParam => 'test'
2016-03-07 00:36:59 -05:00
end
```
2016-03-25 04:30:46 -04:00
2016-03-25 05:15:20 -04:00
2. Passing a `namespace/controller#action` string and a hash.
2016-03-25 04:30:46 -04:00
2016-03-07 00:36:59 -05:00
```ruby
def show
user = User.find params[:id]
2016-03-25 04:30:46 -04:00
2016-03-25 05:15:20 -04:00
js 'Admin/Users', :id => user.id, :myParam => 'test'
2016-03-07 00:36:59 -05:00
end
```
2014-02-15 07:08:17 -05:00
2016-03-25 05:15:20 -04:00
You can access the passed parameters using the `params` property of your Paloma controller.
2014-02-15 07:08:17 -05:00
2016-03-25 04:30:46 -04:00
```js
2016-03-07 00:36:59 -05:00
Paloma.controller('Users', {
show: function(){
alert("User id: " + this.params.id);
2016-03-25 05:15:20 -04:00
alert("String: " + this.params.myParam);
2016-03-07 00:36:59 -05:00
}
});
```
2014-02-15 07:08:17 -05:00
2013-10-12 22:39:27 -04:00
## Preventing Paloma Execution
2013-03-02 11:15:44 -05:00
2016-03-25 04:30:46 -04:00
If you do not want Paloma to execute in a specific Rails Controller action you pass `false` to the `js` method.
2013-03-02 11:15:44 -05:00
2013-10-12 09:36:38 -04:00
```ruby
def edit
@user = User.find params[:id]
js false
end
2013-03-02 11:36:36 -05:00
```
2013-03-02 11:33:26 -05:00
2016-03-25 04:30:46 -04:00
## Controller-wide Setup
2014-02-15 07:08:17 -05:00
2016-03-25 04:30:46 -04:00
You can call `js` outside Rails controller actions for controller-wide settings.
2014-02-15 07:08:17 -05:00
**Example:**
```ruby
class UsersController < ApplicationController
2016-03-25 05:15:20 -04:00
2016-03-25 04:30:46 -04:00
# use Accounts controller instead of Users for all actions.
js 'Accounts'
2014-02-15 07:08:17 -05:00
end
```
2016-03-25 04:30:46 -04:00
Like `before_action` of Rails you can also pass `only` and `except` options.
2014-02-15 07:08:17 -05:00
```ruby
class UsersController < ApplicationController
2016-03-25 04:30:46 -04:00
# Use Admin/Accounts except for show and destroy method
js 'Admin/Accounts', :except => [:show, :destroy]
2014-02-15 07:08:17 -05:00
end
```
**IMPORTANT NOTE:**
2016-03-25 04:30:46 -04:00
If you are going to pass parameters for Controller-wide settings, pass a hash using the `:params` key.
2014-02-15 07:08:17 -05:00
```ruby
class UsersController < ApplicationController
js 'Accounts', :params => {:x => 1, :y => 2, :z => 3}, :only => :show
end
```
2016-03-25 04:30:46 -04:00
### Overriding Controller-wide Setup
2014-02-15 07:08:17 -05:00
2016-03-25 05:15:20 -04:00
If you want to override the controller-wide setup call `js` again inside a controller action. From there, you can override the controller/action or pass additional parameters.
2014-02-15 07:08:17 -05:00
```ruby
class UsersController < ApplicationController
2016-03-25 04:30:46 -04:00
js 'Accounts', :params => {:x => 1}
2014-02-15 07:08:17 -05:00
2016-03-25 04:30:46 -04:00
def new
@user = User.new
# will execute Accounts#register with params {:x => 1, :y => 2}
js :register, :y => 2
end
2014-02-15 07:08:17 -05:00
end
```
2015-04-25 05:52:53 -04:00
## Hook
2016-03-25 05:15:20 -04:00
`insert_paloma_hook` is a helper method that you use in your views to insert Paloma's HTML hook. It is what connects your ruby code to your javascript code. Basically, it contains a javascript code that has embedded ruby in it. That javascript code will register the Rails controller and action to Paloma's engine, then after that it will remove itself from the DOM.
2015-04-25 05:52:53 -04:00
Ideally, you just need to call `insert_paloma_hook` in your layouts, since the layout will always be included in every rendered view. But if you are rendering a view without a layout, make sure to call `insert_paloma_hook` in that view.
2014-06-07 07:47:00 -04:00
2015-05-01 01:06:56 -04:00
2016-03-25 04:30:46 -04:00
## Starting Paloma
Once Paloma's HTML hook is already executed, you can now start Paloma by calling `Paloma.start()` in your javascript code. First, it will execute the HTML hook if not yet executed, then will initialize the correct Paloma controller, execute any before callbacks, and finally execute the correct action if available.
2015-05-01 01:06:56 -04:00
2016-03-25 05:15:20 -04:00
## AJAX
2016-03-25 04:30:46 -04:00
1. Make sure that the AJAX response contains the HTML hook. (use `insert_paloma_hook` )
2016-03-01 22:52:54 -05:00
2. Start Paloma on complete/success.
2015-05-01 01:06:56 -04:00
```js
$.get('http://example.com', function(response){
$('#result').html(response);
2016-03-01 22:52:54 -05:00
Paloma.start();
2015-05-01 01:06:56 -04:00
});
```
2014-06-07 07:47:00 -04:00
## Turbolinks Support
### Execute Paloma when user hits `Back` or `Forward` button.
Paloma executes page-specific javascript by adding a `<script>` tag to the response body. Turbolinks, by default, executes any inline javascript in the response body when you visit a page, so the `<script>` tag appended by Paloma will automatically be executed. However, when Turbolinks restores a page from cache (*this happens when a user hits `Back` or `Forward` button in his browser*) any **inline javascript will not be executed** anymore. This is the intentional behavior of Turbolinks, and it is not a bug. If you want to execute Paloma again when Turbolinks restores a page, do something like this:
```js
$(document).on('page:restore', function(){
2016-03-01 22:52:54 -05:00
Paloma.start();
2014-06-07 07:47:00 -04:00
});
```