handlers-js 0.0.1
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 +20 -0
- data/.travis.yml +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +107 -0
- data/Rakefile +17 -0
- data/handlers-js.gemspec +21 -0
- data/lib/assets/javascripts/handlers.coffee +46 -0
- data/lib/handlers-js.rb +5 -0
- data/spec/javascripts/HandlersSpec.coffee +56 -0
- data/spec/javascripts/TriggerSpec.coffee +51 -0
- data/spec/javascripts/support/jasmine.yml +75 -0
- data/src/jquery-1.8.3.js +9472 -0
- metadata +99 -0
data/.gitignore
ADDED
@@ -0,0 +1,20 @@
|
|
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
|
18
|
+
src/handlers.js
|
19
|
+
spec/javascripts/HandlersSpec.js
|
20
|
+
spec/javascripts/TriggerSpec.js
|
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
language: ruby
|
2
|
+
before_install:
|
3
|
+
- gem install bundler
|
4
|
+
- npm install coffee-script
|
5
|
+
- "export DISPLAY=:99.0"
|
6
|
+
- "sh -e /etc/init.d/xvfb start"
|
7
|
+
|
8
|
+
rvm:
|
9
|
+
- 1.9.3
|
10
|
+
|
11
|
+
branches:
|
12
|
+
only:
|
13
|
+
- master
|
14
|
+
|
15
|
+
notifications:
|
16
|
+
email:
|
17
|
+
recipients:
|
18
|
+
- handlers@erichmenge.com
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Erich Menge
|
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,107 @@
|
|
1
|
+
# Handlers-js [](https://travis-ci.org/erichmenge/handlers-js)
|
2
|
+
|
3
|
+
Handlers-js provides an easy to use, dead simple, unobtrusive Javascript modularization through the Rails asset pipeline.
|
4
|
+
|
5
|
+
What's that mean? That means all you need to do is register your handler, and then call it with `data-handler="MyHandler"` on your HTML tags.
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
* Works "out of the box" with Turbolinks
|
10
|
+
* Easy setup with pjax
|
11
|
+
* Isolation. Code isn't executed where it doesn't belong. No worrying about code leaking by binding to different styles and element IDs.
|
12
|
+
* Consistent patterns.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'handlers-js'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
CoffeeScript is provided via the asset pipeline. A single class called `Handlers` is created.
|
27
|
+
Your asset manifest should look something like this:
|
28
|
+
|
29
|
+
```
|
30
|
+
//= require turbolinks
|
31
|
+
//= require handlers
|
32
|
+
//= require_tree .
|
33
|
+
```
|
34
|
+
|
35
|
+
**IMPORTANT** If you're using Turbolinks, make sure it is included first so that Handlers-js knows about it.
|
36
|
+
|
37
|
+
Now, simply create your CoffeeScript files like so:
|
38
|
+
|
39
|
+
```
|
40
|
+
Handlers.register 'TypeAhead', class
|
41
|
+
constructor: (el) ->
|
42
|
+
url = $(el).data('typeahead-url')
|
43
|
+
property = $(el).data('typeahead-property')
|
44
|
+
value = $(el).data('typeahead-value')
|
45
|
+
|
46
|
+
$(el).typeahead
|
47
|
+
source: (typeahead, query) ->
|
48
|
+
$.ajax
|
49
|
+
dataType: 'json'
|
50
|
+
url: url + query
|
51
|
+
success: (data) ->
|
52
|
+
typeahead.process(data)
|
53
|
+
property: property
|
54
|
+
onselect: (val) ->
|
55
|
+
$(el).val(val.name)
|
56
|
+
$(el).closest('form').submit()
|
57
|
+
|
58
|
+
destroy: ->
|
59
|
+
doSomeCleanup()
|
60
|
+
```
|
61
|
+
|
62
|
+
Then, in your HTML:
|
63
|
+
|
64
|
+
```
|
65
|
+
<span data-handler="TypeAhead" data-typeahead-url="..." data-typeahead-property="..." data-typeahead-value="...">
|
66
|
+
...
|
67
|
+
</span>
|
68
|
+
```
|
69
|
+
|
70
|
+
Need to use more than one Handler on a particular element? No problem. They are comma separated.
|
71
|
+
|
72
|
+
```
|
73
|
+
<span data-handler="TypeAhead,SomethingSpecial" ...></span>
|
74
|
+
```
|
75
|
+
|
76
|
+
### If you're not using Turbolinks
|
77
|
+
|
78
|
+
If you're not using Turbolinks, fear not. Handlers are still easy to use.
|
79
|
+
|
80
|
+
Handlers responds to three triggers:
|
81
|
+
|
82
|
+
* handlers:pageChanged - pageChanged should be triggered when the page is loaded for the first time, this will load any handler found on the page.
|
83
|
+
* handlers:pageUpdating - This should be triggered when the page is changing, it must be passed the scope it should perform on
|
84
|
+
* handlers:pageUpdated - This should be triggered when the page change is complete, it must be passed the scope it should perform on
|
85
|
+
|
86
|
+
A pjax example:
|
87
|
+
|
88
|
+
``` main.coffee
|
89
|
+
|
90
|
+
$(document).on 'pjax:start', ->
|
91
|
+
$(document).trigger 'handlers:pageUpdating', '[data-pjax-container]'
|
92
|
+
|
93
|
+
$(document).on 'pjax:end', ->
|
94
|
+
$(document).trigger 'handlers:pageUpdated', '[data-pjax-container]'
|
95
|
+
|
96
|
+
$ ->
|
97
|
+
$(document).trigger 'handlers:pageChanged'
|
98
|
+
```
|
99
|
+
|
100
|
+
|
101
|
+
## Contributing
|
102
|
+
|
103
|
+
1. Fork it
|
104
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
105
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
106
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
107
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'jasmine'
|
5
|
+
load 'jasmine/tasks/jasmine.rake'
|
6
|
+
rescue LoadError
|
7
|
+
task :jasmine do
|
8
|
+
abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
task :build_js do
|
13
|
+
`coffee -o src -c lib/assets/javascripts/handlers.coffee`
|
14
|
+
`coffee -c spec/javascripts`
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => [:build_js, 'jasmine:ci']
|
data/handlers-js.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "handlers-js"
|
7
|
+
gem.version = "0.0.1"
|
8
|
+
gem.authors = ["Erich Menge"]
|
9
|
+
gem.email = ["erich.menge@me.com"]
|
10
|
+
gem.description = %q{Easy, modular UJS for your Rails apps}
|
11
|
+
gem.summary = %q{Easy, modular UJS for your Rails apps}
|
12
|
+
gem.homepage = "https://github.com/erichmenge/handlers-js"
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
|
19
|
+
gem.add_development_dependency('rake')
|
20
|
+
gem.add_development_dependency('jasmine')
|
21
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class @Handlers
|
2
|
+
@handlers = {}
|
3
|
+
|
4
|
+
@register: (handler, registered_class) ->
|
5
|
+
throw "No constructor on " + handler unless registered_class.constructor
|
6
|
+
@handlers[handler] = registered_class
|
7
|
+
|
8
|
+
@instantiate: (handlers, element) ->
|
9
|
+
handlers = handlers.replace(/\s/g, '').split(',')
|
10
|
+
element.handlers = []
|
11
|
+
$.each handlers, (index, handler) =>
|
12
|
+
if @handlers[handler]
|
13
|
+
instance = new @handlers[handler](element)
|
14
|
+
element.handlers.push instance
|
15
|
+
else
|
16
|
+
throw "Unknown handler " + handler
|
17
|
+
|
18
|
+
@destroy: (instances) ->
|
19
|
+
$.each instances, (index, instance) ->
|
20
|
+
instance.destroy() if instance.destroy
|
21
|
+
|
22
|
+
@unregister_all: ->
|
23
|
+
@handlers = {}
|
24
|
+
|
25
|
+
$(document).on 'handlers:pageChanged', ->
|
26
|
+
$('[data-handler]').each ->
|
27
|
+
Handlers.instantiate $(this).attr('data-handler'), this
|
28
|
+
|
29
|
+
$(document).on 'handlers:pageUpdated', (event, scope) ->
|
30
|
+
$(scope).find('[data-handler]').each ->
|
31
|
+
Handlers.instantiate $(this).attr('data-handler'), this
|
32
|
+
|
33
|
+
$(document).on 'handlers:pageUpdating', (event, scope) ->
|
34
|
+
$(scope).find('[data-handler]').each ->
|
35
|
+
Handlers.destroy @handlers if @handlers
|
36
|
+
delete @handlers if @handlers
|
37
|
+
|
38
|
+
if typeof(Turbolinks) != undefined
|
39
|
+
$(document).on 'page:fetch', ->
|
40
|
+
$(document).trigger 'handlers:pageUpdating', 'body'
|
41
|
+
|
42
|
+
$(document).on 'page:change', ->
|
43
|
+
$(document).trigger 'handlers:pageUpdated', 'body'
|
44
|
+
|
45
|
+
$ ->
|
46
|
+
$(document).trigger 'handlers:pageChanged'
|
data/lib/handlers-js.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
describe "Handlers", =>
|
2
|
+
el = null
|
3
|
+
|
4
|
+
beforeEach =>
|
5
|
+
el = {}
|
6
|
+
|
7
|
+
afterEach =>
|
8
|
+
Handlers.unregister_all()
|
9
|
+
|
10
|
+
it "should be defined", ->
|
11
|
+
expect(Handlers).toBeDefined()
|
12
|
+
|
13
|
+
it "should register a handler", ->
|
14
|
+
Handlers.register 'Foo', class
|
15
|
+
expect(Handlers.handlers['Foo']).toBeDefined()
|
16
|
+
|
17
|
+
describe "multiple handlers", ->
|
18
|
+
|
19
|
+
beforeEach ->
|
20
|
+
Handlers.register 'Foo', class
|
21
|
+
Handlers.register 'Bar', class
|
22
|
+
|
23
|
+
afterEach ->
|
24
|
+
expect(Handlers.handlers['Foo']).toBeDefined()
|
25
|
+
expect(Handlers.handlers['Bar']).toBeDefined()
|
26
|
+
|
27
|
+
it "should instantiate them", ->
|
28
|
+
expect(-> Handlers.instantiate('Foo, Bar', el)).not.toThrow()
|
29
|
+
|
30
|
+
it "should allow spaces", ->
|
31
|
+
expect(-> Handlers.instantiate('Foo, Bar', el)).not.toThrow()
|
32
|
+
|
33
|
+
it "should attach to an element", ->
|
34
|
+
Handlers.register 'Foo', class
|
35
|
+
expect(el.handlers).not.toBeDefined()
|
36
|
+
expect(-> Handlers.instantiate('Foo', el)).not.toThrow()
|
37
|
+
expect(el.handlers).toBeDefined()
|
38
|
+
|
39
|
+
it "should throw if the handler isn't known", ->
|
40
|
+
expect(-> Handlers.instantiate('Foo', el)).toThrow()
|
41
|
+
|
42
|
+
it "should destroy if the destroy function is available", ->
|
43
|
+
Handlers.register 'Foo', class
|
44
|
+
constructor: (el) ->
|
45
|
+
destroy: ->
|
46
|
+
|
47
|
+
Handlers.instantiate('Foo', el)
|
48
|
+
spyOn(el.handlers[0], 'destroy')
|
49
|
+
Handlers.destroy(el.handlers)
|
50
|
+
expect(el.handlers[0].destroy).toHaveBeenCalled()
|
51
|
+
|
52
|
+
it "should not throw if there is not a destructor", ->
|
53
|
+
Handlers.register 'Foo', class
|
54
|
+
Handlers.instantiate 'Foo', el
|
55
|
+
expect(-> Handlers.destroy(el.handlers)).not.toThrow()
|
56
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
describe 'Triggers', =>
|
2
|
+
beforeEach =>
|
3
|
+
$('body').append('<span style="display: none"; id="foospan" data-handler="Foo"></span>')
|
4
|
+
Handlers.register 'Foo', class
|
5
|
+
constructor: (el) ->
|
6
|
+
@el = $(el)
|
7
|
+
$(el).html('filled')
|
8
|
+
destroy: ->
|
9
|
+
@el.html("destroyed")
|
10
|
+
|
11
|
+
afterEach =>
|
12
|
+
$('#foospan').remove()
|
13
|
+
Handlers.unregister_all
|
14
|
+
|
15
|
+
describe 'When the page changes', ->
|
16
|
+
it 'should trigger the event', ->
|
17
|
+
$(document).trigger 'handlers:pageChanged'
|
18
|
+
expect($('#foospan').html()).toEqual "filled"
|
19
|
+
|
20
|
+
describe 'When page is updated', ->
|
21
|
+
it 'should trigger the event', ->
|
22
|
+
$(document).trigger 'handlers:pageUpdated', 'body'
|
23
|
+
expect($('#foospan').html()).toEqual "filled"
|
24
|
+
|
25
|
+
it 'should maintain scope', ->
|
26
|
+
$('#foospan').html('')
|
27
|
+
$('body').append(
|
28
|
+
'<span style="display: none"; id="onlyscope">
|
29
|
+
<span style="display: none"; id="scopedspan" data-handler="Foo"></span>
|
30
|
+
</span>'
|
31
|
+
)
|
32
|
+
$(document).trigger 'handlers:pageUpdated', '#onlyscope'
|
33
|
+
expect($('#foospan').html()).toEqual ""
|
34
|
+
expect($('#scopedspan').html()).toEqual "filled"
|
35
|
+
|
36
|
+
describe 'When page is changing', ->
|
37
|
+
it 'should destroy', ->
|
38
|
+
$(document).trigger('handlers:pageChanged')
|
39
|
+
$(document).trigger('handlers:pageUpdating', 'body')
|
40
|
+
expect($('#foospan').html()).toEqual "destroyed"
|
41
|
+
|
42
|
+
it 'should maintain scope', ->
|
43
|
+
$('body').append(
|
44
|
+
'<span style="display: none"; id="onlyscope">
|
45
|
+
<span style="display: none"; id="scopedspan" data-handler="Foo"></span>
|
46
|
+
</span>'
|
47
|
+
)
|
48
|
+
$(document).trigger('handlers:pageChanged')
|
49
|
+
$(document).trigger('handlers:pageUpdating', '#onlyscope')
|
50
|
+
expect($('#foospan').html()).toEqual "filled"
|
51
|
+
expect($('#scopedspan').html()).toEqual "destroyed"
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# src_files
|
2
|
+
#
|
3
|
+
# Return an array of filepaths relative to src_dir to include before jasmine specs.
|
4
|
+
# Default: []
|
5
|
+
#
|
6
|
+
# EXAMPLE:
|
7
|
+
#
|
8
|
+
# src_files:
|
9
|
+
# - lib/source1.js
|
10
|
+
# - lib/source2.js
|
11
|
+
# - dist/**/*.js
|
12
|
+
#
|
13
|
+
src_files:
|
14
|
+
- src/jquery-1.8.3.js
|
15
|
+
- src/handlers.js
|
16
|
+
|
17
|
+
# stylesheets
|
18
|
+
#
|
19
|
+
# Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.
|
20
|
+
# Default: []
|
21
|
+
#
|
22
|
+
# EXAMPLE:
|
23
|
+
#
|
24
|
+
# stylesheets:
|
25
|
+
# - css/style.css
|
26
|
+
# - stylesheets/*.css
|
27
|
+
#
|
28
|
+
stylesheets:
|
29
|
+
|
30
|
+
# helpers
|
31
|
+
#
|
32
|
+
# Return an array of filepaths relative to spec_dir to include before jasmine specs.
|
33
|
+
# Default: ["helpers/**/*.js"]
|
34
|
+
#
|
35
|
+
# EXAMPLE:
|
36
|
+
#
|
37
|
+
# helpers:
|
38
|
+
# - helpers/**/*.js
|
39
|
+
#
|
40
|
+
helpers:
|
41
|
+
- 'helpers/**/*.js'
|
42
|
+
# spec_files
|
43
|
+
#
|
44
|
+
# Return an array of filepaths relative to spec_dir to include.
|
45
|
+
# Default: ["**/*[sS]pec.js"]
|
46
|
+
#
|
47
|
+
# EXAMPLE:
|
48
|
+
#
|
49
|
+
# spec_files:
|
50
|
+
# - **/*[sS]pec.js
|
51
|
+
#
|
52
|
+
spec_files:
|
53
|
+
- '**/*[sS]pec.js'
|
54
|
+
|
55
|
+
# src_dir
|
56
|
+
#
|
57
|
+
# Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
|
58
|
+
# Default: project root
|
59
|
+
#
|
60
|
+
# EXAMPLE:
|
61
|
+
#
|
62
|
+
# src_dir: public
|
63
|
+
#
|
64
|
+
src_dir:
|
65
|
+
|
66
|
+
# spec_dir
|
67
|
+
#
|
68
|
+
# Spec directory path. Your spec_files must be returned relative to this path.
|
69
|
+
# Default: spec/javascripts
|
70
|
+
#
|
71
|
+
# EXAMPLE:
|
72
|
+
#
|
73
|
+
# spec_dir: spec/javascripts
|
74
|
+
#
|
75
|
+
spec_dir:
|