observejs 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 34f7e2b0d3b0c92e4a99b441e4e47ef15ad3744c
4
- data.tar.gz: 0b4ca8788f5915d2b925d68a1131560315195865
3
+ metadata.gz: 2761d7377eeaa19bed746a3c8638135b1a5e1ffa
4
+ data.tar.gz: 045c433af158e4d738bb49d4a36d22b50cc11801
5
5
  SHA512:
6
- metadata.gz: 3f74f38db3a194c310dc5dcfa10996fbf2d68691ee288ff62b1247508fecd2a2e261d74ae8d803e7a3645a4973f55899249d1baa61b4508bca4b72bcd090b982
7
- data.tar.gz: c2eb85285421fdf3ef7e5b24c559e4967a5e090ee93d1f1a5a53890237f14c54ae1091ac63ae83c28bae6ec8205f451cabf8398f5a0da44860aaa1beff9ea815
6
+ metadata.gz: 723c9abade49bc513f23aa7e8bd526d7223389652452af425c8d2e3aeb6148e9a7f1c58acea02537a560fc7873d8e4cf3001299b7e854a149f804c05f5650ef4
7
+ data.tar.gz: 528c2585a2e94b8f74eaaaa5cf07c1e5e314c5f7f48516daa95cc7561b8a536242a1d873ed4ef16439fbd3477974fefc268eeae58e49f29af96fed925da30c07
data/README.md CHANGED
@@ -1,65 +1,67 @@
1
1
  # ObserveJS
2
2
 
3
- Event based JavaScript framework tailored made for Ruby on rails.
3
+ ObserveJS is an event-based library created for Ruby On Rails to help people build interactive application **without committing to a Single Page Application (SPA)**.
4
4
 
5
- ## Installation
5
+ Based on Custom Elements, ObserveJS takes an innovative approach that re-use views and partials and leverages custom events to make you change application to any server response.
6
6
 
7
- Add this line to your application's Gemfile:
7
+ This framework is not like any other JS alternative. It brings concepts from different paradigms and merges them together. It's not as simple as building some JS classes and have everything fed via JSON. Obviously, this won't be for everyone.
8
8
 
9
- ```ruby
10
- gem 'observejs'
11
- ```
9
+ To understand what ObserveJS is all about, you need to understand the foundation on which ObserveJS was built.
12
10
 
13
- Then add this line to application.js
11
+ ## Javascript Classes bound like Custom Elements
14
12
 
15
- ```js
16
- //= require 'observejs'
17
- ```
18
- ## Usage
13
+ You may not know about Custom elements, these guys aren't as popular as React but they aren't useless. Trust me. What you need to know here is that by defining an attribute on an element, you can let ObserveJS instantiate a JavaScript class that will be bound to this object. Here's an example:
19
14
 
20
- ObserveJS is an event based framework that manages the life cycle of JavaScript objects. Here's a simple Todo where you can dynamically add/remove items on the list.
15
+ ```html
16
+ <div class='datepicker' as='Datepicker'>
17
+ </div>
18
+ ```
21
19
 
22
- ```erb
23
- <!-- views/todos/index.html.erb -->
24
- <%= content_tag :ol, as: 'Todo.List', do %>
25
- <%= render @todos %>
26
- <% end %>
20
+ Here, you defined an element with the ```as``` attribute. That attribute is special as it will be detected by ObserveJS. It will locate a Javascript class that has been declared the same name and instantiate it. Here's how it would look in JS:
21
+
22
+ ```javascript
23
+ ObserveJS.bind('Datepicker', class {
24
+ // This method is called after the class is configured and attached to
25
+ // the element
26
+ loaded() {
27
+ console.log("I'm instantiated")
28
+
29
+ this.element()
30
+ // <div class='datepicker' as='Datepicker'>
31
+
32
+ //This look for data-loading
33
+ this.observe('loading', this.changeStatus)
34
+ }
35
+
36
+ changeStatus(mutation) {
37
+ }
38
+ })
27
39
  ```
28
40
 
29
- ```coffee
30
- # assets/javascripts/todos/list.js.coffee
31
- ObserveJS.bind 'Todo.List', class
32
- # @element() always return the element to which your object is bound.
41
+ The object instantiated inherit a few methods that are shown below. The most important method of all is probably the ```this.element()``` method. It returns the element that was bound to this class.
33
42
 
34
- loaded: =>
35
- @element().on 'todos:create', @add
36
- @element().on 'todos:destroy', @delete
43
+ Now, if you would have the DOM element rendered in a page, automatically, the associated JavaScript class would get instantiated and initialized. Those objects have default API that makes your life easier.
37
44
 
38
- add: (e) =>
39
- @element().appendChild(e.html)
45
+ ## JS Object's instance methods
40
46
 
41
- delete: (e) =>
42
- @element().querySelector("[tid=#{e.todoId}]")?.remove()
47
+ ### ```this.element()```
43
48
 
44
- ```
49
+ Returns the element bound to the JS object.
45
50
 
46
- ```ruby
47
- #views/todos/create.js.erb
48
- e.html = "<%= j render(@todo) %>".toHTML()
49
- ```
51
+ ### ```this.on(event_name, callback)```
50
52
 
51
- ```ruby
52
- #views/todos/destroy.js.erb
53
- e.todoId = <%= @todo.id %>
54
- ```
53
+ Bind an event to the specified callback. The event is bound to the element associated with the class. In the example above, this would mean that the event would be bound to the ```div``` element. The callback will be fired only if an event matching its name bubbles up to the element or if an event is fired directly on this event.
54
+
55
+ ### ```this.on(event_name, target, callback)```
56
+
57
+ Bind an event on a **descendant** of the element associated with the given class. If the target is not a descendant, an Exception will be raised. This is basically the same thing as the previous method except that you can bind it to a descendant.
58
+
59
+ ### ```this.when(event_name, callback)```
55
60
 
56
- Some notes:
61
+ Bind an event to ```document```. This should be used only when dealing with server side events or when you need to capture an event from another element that is not a descendant.
57
62
 
58
- - Automatic instantiation. No need to wrap things in DOMContentReady anymore.
59
- - Events are built following the "controller:action" pattern.
60
- - A callback (@loaded) is called right after ObserveJS has instantiated an object.
61
- - In *.js.erb, an event is created. You can set HTML to the event object.
62
- - To ease the process, a toHTML() method has been added to the String object (JS).
63
- - You need to register any class you create through the ```ObserveJS.bind 'name', Class```. The name is the attribute you set in your DOM.
63
+ All those methods are available to configure your object at any time. You will probably find it useful to setup your callabcks in the ```loaded()``` method as it is **the callback used by ObserveJS when the object is configured**.
64
64
 
65
+ ### ```this.observe(attribute, callback)```
65
66
 
67
+ Bind a callback to a change made to data-* attribute on ```this.element()```. You can call this on different attribute.
@@ -15,14 +15,11 @@ class ObserveJS
15
15
  bind: (name, kls) =>
16
16
  @cache[name] = kls
17
17
 
18
- kls.prototype.template = () ->
18
+ kls.prototype.template = (selector) ->
19
19
  tmpl = @element().querySelector("template[for='#{name}']")
20
20
  unless tmpl?
21
21
  throw "Template Error: Couldn't find a template matching #{name}"
22
22
  return
23
- tmpl
24
-
25
- kls.prototype.retrieve = (selector) ->
26
- @element().querySelector(selector) || @template().content.querySelector(selector).cloneNode(true)
23
+ (tmpl.content || tmpl).querySelector(selector).cloneNode(true)
27
24
 
28
25
  window.ObserveJS = new ObserveJS()
@@ -11,7 +11,7 @@ class Creator
11
11
  model = el.getAttribute(ObserveJS.attributeName)
12
12
  if ObserveJS.cache[model]?
13
13
  if el.instance?
14
- el.loaded()
14
+ el.instance.loaded()
15
15
  return
16
16
 
17
17
  el.instance = new ObserveJS.cache[model](el)
@@ -19,24 +19,47 @@ class Creator
19
19
  el.instance.element = ->
20
20
  el
21
21
 
22
+ observer = new ObserveJS.Observer(el.instance)
23
+
24
+ el.instance.observe = (observer, key, callback) ->
25
+ observer.bind(key, callback.bind(el.instance))
26
+
27
+ el.instance.observe = el.instance.observe.bind(el.instance, observer)
28
+ el.instance.observe.observer = observer
29
+
22
30
  el.instance.on = (event, target, callback) ->
23
- if callback?
24
- el.instance.on.events.push([event, target, callback])
25
- else
31
+ if !callback?
26
32
  callback = target
27
33
  target = el
34
+
35
+ if !el.contains(target)
36
+ throw "error: #{model} is trying to bind an event on a target that isn't a children, or itself. If you desire to bind an event to the document, use when()"
37
+ return
38
+ callback = callback.bind(el.instance)
39
+
40
+ el.instance.on.events.push([event, target, callback])
28
41
  target.addEventListener(event, callback)
29
42
 
43
+ el.instance.when = (event, callback) ->
44
+ callback = callback.bind(el.instance)
45
+
46
+ el.instance.on.events.push([event, document, callback])
47
+ document.addEventListener(event, callback)
48
+
30
49
  el.instance.on.events = []
31
50
 
32
51
  if el.instance.loaded?
33
52
  el.instance.loaded()
34
53
 
35
54
  else
36
- throw "error: #{model} is not registered. Add your model with ObserveJS.Models.add(#{model})"
55
+ throw "error: #{model} is not registered. Add your model with ObserveJS.bind(#{model}, {})"
37
56
 
38
57
  destroy: (el) =>
39
58
  el.instance.on.events?.forEach (event) ->
40
59
  event[1].removeEventListener(event[0], event[2])
41
60
 
61
+ el.instance.unloaded?()
62
+ el.instance.observe.observer.disconnect()
63
+ delete el.instance
64
+
42
65
  @ObserveJS.Creator = new Creator()
@@ -0,0 +1,22 @@
1
+ class @ObserveJS.Observer
2
+ constructor: (model) ->
3
+ @keys = {}
4
+ @observer = new MutationObserver(@mutated.bind(this, model))
5
+ @observer.observe(model.element(), {
6
+ childList: false
7
+ characterData: false
8
+ attributes: true
9
+ })
10
+
11
+ bind: (key, callback) ->
12
+ @keys["data-#{key}"] = callback
13
+
14
+ mutated: (model, mutations) ->
15
+ for mutation in mutations
16
+ if (callback = @keys[mutation.attributeName])?
17
+ callback(mutation)
18
+
19
+ disconnect: =>
20
+ @observer.disconnect()
21
+
22
+
@@ -31,6 +31,26 @@ class XHRData
31
31
 
32
32
  formData
33
33
 
34
+ urlEncoded: (action) =>
35
+ parser = document.createElement('a')
36
+ parser.href = action
37
+ params = parser.search.substring(1).split('&')
38
+
39
+ for key in @keys()
40
+ params.push "#{key}=#{@value(key)}"
41
+
42
+ if @form?
43
+ for element in @form.elements
44
+ unless element.hasAttribute('name')
45
+ continue
46
+
47
+ type = element.getAttribute("type").toUpperCase() || 'TEXT'
48
+ if (type != 'FILE' && type != 'RADIO' && type != 'CHECKBOX') || element.checked
49
+ params.push "#{encodeURIComponent(element.name)}=#{encodeURIComponent(element.value)}"
50
+
51
+ parser.search = "?#{params.join("&")}"
52
+ parser.href
53
+
34
54
  class Response
35
55
  constructor: (@xhr) ->
36
56
  @xhr.request.addEventListener 'load', @process
@@ -70,6 +90,11 @@ class XHR
70
90
 
71
91
  @method = el.getAttribute('method') || 'GET'
72
92
 
93
+ open: (method, action) =>
94
+ @request.open @method, action
95
+ @request.setRequestHeader 'accept', "*/*;q=0.5, #{@script}"
96
+ @request.setRequestHeader 'X-Requested-With', "XMLHttpRequest"
97
+
73
98
  send: =>
74
99
  action = @request.element.getAttribute('action') || @request.element.getAttribute('href')
75
100
 
@@ -77,27 +102,18 @@ class XHR
77
102
  throw "Cannot send a request to the server if the element isn't a Form or if the element doesn't have the HREF attributes: <div href>"
78
103
  return
79
104
 
80
- if @method == 'GET' && @data.any()
81
- parser = document.createElement('a')
82
- parser.href = action
83
- params = parser.search.substring(1).split('&')
84
-
85
- for key in @data.keys()
86
- params.push "#{key}=#{@data.value(key)}"
87
-
88
- parser.search = "?#{params.join("&")}"
89
-
90
- action = parser.href
91
105
 
92
- @request.open @method, action
93
- @request.setRequestHeader 'accept', "*/*;q=0.5, #{@script}"
94
- @request.setRequestHeader 'X-Requested-With', "XMLHttpRequest"
106
+ if /post|put|delete/i.test(@method)
107
+ @open(@method, action)
95
108
 
96
- if @method != 'GET'
97
109
  token = document.querySelector('meta[name=csrf-token]').getAttribute('content')
98
110
  @request.setRequestHeader 'X-CSRF-Token', token
99
111
 
100
- @request.send(@data.serialize())
112
+ @request.send(@data.serialize())
113
+ else
114
+ action = @data.urlEncoded(action)
115
+ @open(@method, action)
116
+ @request.send()
101
117
 
102
118
 
103
119
  ObserveJS.XHR = XHR
@@ -1,7 +1,9 @@
1
+ #= require_tree './polyfills'
1
2
  #= require 'observejs/ext'
2
3
  #= require 'observejs/base'
3
4
  #= require 'observejs/watcher'
4
5
  #= require 'observejs/creator'
6
+ #= require 'observejs/observer'
5
7
  #= require 'observejs/xhr'
6
8
 
7
9
  if document.readyState == 'complete'
@@ -0,0 +1,12 @@
1
+ if typeof window.CustomEvent == "function"
2
+ return false
3
+
4
+ CustomEvent = ( event, params ) ->
5
+ params = params || { bubbles: false, cancelable: false, detail: undefined }
6
+ evt = document.createEvent( 'CustomEvent' )
7
+ evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail )
8
+ return evt
9
+
10
+ CustomEvent.prototype = window.Event.prototype
11
+
12
+ window.CustomEvent = CustomEvent
@@ -1,3 +1,3 @@
1
1
  module ObserveJS
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
data/test/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/pothibo/Develop/observejs
3
3
  specs:
4
- observejs (0.0.6)
4
+ observejs (0.0.7)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -162,3 +162,6 @@ DEPENDENCIES
162
162
  turbolinks
163
163
  uglifier (>= 1.3.0)
164
164
  web-console (~> 2.0)
165
+
166
+ BUNDLED WITH
167
+ 1.11.2
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: observejs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pier-Olivier Thibault
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-26 00:00:00.000000000 Z
11
+ date: 2016-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -83,8 +83,10 @@ files:
83
83
  - lib/observejs/app/assets/javascripts/observejs/base.js.coffee
84
84
  - lib/observejs/app/assets/javascripts/observejs/creator.js.coffee
85
85
  - lib/observejs/app/assets/javascripts/observejs/ext.js.coffee
86
+ - lib/observejs/app/assets/javascripts/observejs/observer.js.coffee
86
87
  - lib/observejs/app/assets/javascripts/observejs/watcher.js.coffee
87
88
  - lib/observejs/app/assets/javascripts/observejs/xhr.js.coffee
89
+ - lib/observejs/app/assets/javascripts/polyfills/event.coffee
88
90
  - lib/observejs/app/views/layouts/application.js.erb
89
91
  - lib/observejs/railtie.rb
90
92
  - lib/observejs/version.rb
@@ -154,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
156
  version: '0'
155
157
  requirements: []
156
158
  rubyforge_project:
157
- rubygems_version: 2.4.5
159
+ rubygems_version: 2.4.5.1
158
160
  signing_key:
159
161
  specification_version: 4
160
162
  summary: Event based JavaScript framework tailored for Ruby on rails.