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 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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in handlers-js.gemspec
4
+ gemspec
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 [![Build Status](https://travis-ci.org/erichmenge/handlers-js.png?branch=master)](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']
@@ -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'
@@ -0,0 +1,5 @@
1
+ module Handlers
2
+ module Rails
3
+ class Engine < ::Rails::Engine; end
4
+ end
5
+ end
@@ -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: