handlers-js 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: