Punchbox is a dead-simple way to add page-specific JavaScript to your Rails project.
The goal for this project is to have a focused scope (page-specific JS and nothing else), be as lightweight as possible, have no dependencies, and to run on almost any browser that runs JS.
Punchbox's syntax is a spiritual successor to Paloma and is otherwise inspired by a project I've contributed to in the past, seed_tray.
Looking for a friendly walkthrough? Check here
Punchbox should work on Rails 4+ and really any Ruby version that's supported by your version of Rails. There's really nothing fancy happening Ruby-side.
The JavaScript is pure without any dependencies (no jQuery! 🎉). It should work down to IE9, thereby working on 98% of browsers.
Punchbox works with or without Turbolinks.
The JavaScript is only ~840 bytes minified and gzipped.
You know the drill. Add this line to your application's Gemfile:
gem 'punchbox'
And then execute:
$ bundle
Or install it yourself as:
$ gem install punchbox
Once you've done that, require Punchbox before tree in your main JavaScript file.
// ...
//= require punchbox
//= require_tree .
Finally, include the punchbox_attributes
hooks in your main <body>
tag.
<body <%= punchbox_attributes %>>
<%= yield %>
</body>
You might also include the attributes with punchbox_data
, which returns a plain ruby data:
object. Useful for using with templating languages like Erb, Haml and Slim.
body *punchbox_data
== yield
Punchbox's syntax is very similar to that of Paloma's. To run JS on a certain page, you call Punchbox like so:
Punchbox.on(<controller: string>, <callable>);
Important
Punchbox automatically runs your code after your document is ready, negating the need for $(document).ready
and the like. If this is a problem, please make an issue and I'll consider changing this behaviour.
controller
should be a string or a function that returns a string. It should be the exact name of the controller (plus namespace) that you want your code to run on. It should be ClassCase (PascalCase) only.
For example, if your controller is PostsController
, you'd enter Posts
. If your controller is AdminPanelsController
, you'd enter AdminPanels
.
Namespacing is accomplished via forward slashes.
If your controller is AdminPanel::Settings::UserManagersController
, you'd enter AdminPanel/Settings/UserManagers
.
callable
can be a function, class, or object. Classes are the preferred convention, but of course you can use whatever is compatible with your current workflow.
Functions should be named after the actions on which they should run. A function index
would run when the index
action is invoked.
The exception is controller
. Punchbox treats functions named controller
in a special way and runs them on every action in a given Rails controller.
In all examples I'll be targeting the Posts
controller. Remember that the name of your callable
or your JS filepath don't have anything to do with Punchbox's functionality. However, I'll be naming the callables after the controllers to keep up with the preferred convention.
ES2015+ (class syntax)
class Posts {
controller() {
console.log('Hello from every action on a controller!');
}
index() {
console.log('Hello from just the index action!');
}
// ...
}
Punchbox.on('Posts', Posts); // Notice that you don't instantiate the class
Function syntax
function Posts() {
// ...
};
Posts.prototype.controller = function() {
console.log('Hello from every action on a controller!');
};
Posts.prototype.index = function() {
console.log('Hello from just the index action!');
};
Punchbox.on('Posts', Posts); // Notice that you don't instantiate the function
Object syntax
var Posts = {
controller: function() {
console.log('Hello from every action on a controller!');
},
index: function() {
console.log('Hello from just the index action!');
}
}
Punchbox.on('Posts', Posts);
CoffeeScript
class Posts
controller: ->
console.log 'Hello from every action on a controller!'
index: ->
console.log 'Hello from just the index action!'
Punchbox.on('Posts', Posts) # Notice that you don't instantiate the class
Every time a controller or action function is run, some events on document
fire.
These events are punchbox:<controller>:run
and punchbox:<controller>:<action>:run
. These both run when their respective functions would run.
Keep in mind that the events are snake_case
with slashes preserved.
For example, you would listen to the Posts
controller trigger like so:
document.addEventListener('punchbox:posts:run', () => {
console.log('Posts controller ran!');
})
and you'd listen to the Posts
index
trigger like so:
document.addEventListener('punchbox:posts:index:run', () => {
console.log('Posts index ran!');
})
If you want to contribute, don't hesitate to create an issue or PR! Since this project is in it's infancy, your input could help shape the project as a whole!
Please note that the magic happens inside app/assets/javascripts/punchbox.es6
. punchbox.js
is then created via Babel before deployment. If you make a PR, please only edit punchbox.es6
.
Bug reports and pull requests are welcome on GitHub at https://github.com/kieraneglin/punchbox/. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.