lib/bowline/binders.rb in bowline-0.4.6 vs lib/bowline/binders.rb in bowline-0.5.0
- old
+ new
@@ -1,166 +1,203 @@
module Bowline
module Binders
class Base
+ extend Bowline::Watcher::Base
+ extend Bowline::Desktop::Bridge::ClassMethods
+ js_expose
+
class << self
- # See Bowline::js
- def js
- Bowline::js
+ def windows
+ @windows ||= []
end
-
- # Equivalent of the 'jQuery' function
- def jquery
- @@jquery ||= JQuery.new
+
+ # Called by JS when first bound
+ def setup(window)
+ self.windows << window
+ self.items = all
+ true
end
-
- # See the Observer class
- def observer
- @observer ||= Observer.new
- end
- # See Bowline::logger
- def logger
- Bowline::logger
+ def js_invoke(window, method, *args)
+ if method == :setup
+ setup(window)
+ else
+ send(method, *args)
+ end
end
-
- # See Bowline::show_view
- def show_view(*args)
- Bowline::show_view(*args)
+
+ def instance_invoke(id, meth, *args) #:nodoc:
+ self.new(id).send(meth, *args)
end
- def params
- @params
+ def find(id)
+ klass.find(id)
end
-
- def params=(p) #:nodoc:
- case p
- when String
- # Params comes in a string (since it's a
- # serialized form) - we need to make it into
- # a nestled hash. Stolen from Ramaze
- m = proc {|_,o,n|o.merge(n,&m)}
- @params = params.inject({}) do |hash, (key, value)|
- parts = key.split(/[\]\[]+/)
- hash.merge(parts.reverse.inject(value) { |x, i| {i => x} }, &m)
- end
- else
- @params = p
- end
+
+ def all
+ klass.all
end
- def elements
- @elements
+ def items=(items) #:nodoc:
+ bowline.populate(name, items.to_js).call
end
- def setup(d) #:nodoc:
- @elements ||= []
- @elements << d
- self.item_sync!
+ def created(item) #:nodoc:
+ bowline.created(
+ name,
+ item.id,
+ item.to_js
+ ).call
end
- def trigger(event, data = nil)
- @elements ||= []
- @elements.map {|e|
- e.trigger(format_event(event), data)
- }
+ def updated(item) #:nodoc:
+ bowline.updated(
+ name,
+ item.id,
+ item.to_js
+ ).call
end
- def loading(&block)
- trigger(:loading, true)
- yield
- trigger(:loading, false)
+ def removed(item) #:nodoc:
+ bowline.removed(
+ name,
+ item.id
+ ).call
end
+
+ protected
+ # Associate the binder with a model
+ # to setup callbacks so changes to the
+ # model are automatically reflected in
+ # the view. Usage:
+ # expose Post
+ #
+ # When the exposed class is created/updated/deleted
+ # the binder's callbacks are executed and the view
+ # updated accordingly.
+ #
+ # klass needs to respond to:
+ # * all
+ # * find(id)
+ # * after_create(method)
+ # * after_update(method)
+ # * after_destroy(method)
+ #
+ # klass instance needs to respond to:
+ # * id
+ #
+ # You can override .to_js on the model instance
+ # in order to return specific attributes for the view
+ def expose(klass)
+ @klass = klass
+ @klass.after_create(method(:created))
+ @klass.after_update(method(:updated))
+ @klass.after_destroy(method(:removed))
+ end
+
+ # Returns class set by the 'expose' method
+ def klass
+ @klass || raise("klass not set - see expose method")
+ end
+
+ # JavaScript proxy to the page:
+ # page.myFunc(1,2,3).call
+ def page
+ Bowline::Desktop::Proxy.new(
+ windows.length == 1 ? windows.first : windows
+ )
+ end
+
+ # JavaScript proxy to the Bowline object:
+ # bowline.log("msg").call
+ def bowline
+ page.Bowline
+ end
- def instance(el) #:nodoc:
- self.new(el).method(:send)
- end
-
- def inherited(child) #:nodoc:
- return if self == Bowline::Binders::Base
- return if child == Bowline::Binders::Singleton
- return if child == Bowline::Binders::Collection
- name = child.name.underscore
- name = name.split('/').last
- js.send("bowline_#{name}_setup=", child.method(:setup))
- js.send("bowline_#{name}_instance=", child.method(:instance))
- js.send("bowline_#{name}=", child.method(:send))
- end
+ # Javascript proxy to jQuery:
+ # jquery.getJSON("http://example.com")
+ def jquery
+ page.jQuery
+ end
- def format_event(name) #:nodoc:
- name.is_a?(Array) ?
- name.join('.') :
- name.to_s
- end
+ # See Bowline::logger
+ def logger
+ Bowline::logger
+ end
+
+ # Trigger events on all elements
+ # bound to this binder:
+ # trigger(:reload, {:key => :value})
+ def trigger(event, data = nil)
+ bowline.trigger(
+ name,
+ format_event(event),
+ data
+ ).call
+ end
+
+ # Helper method to trigger a loading
+ # event either side of a block:
+ # loading {
+ # # Slow code, e.g. http call
+ # }
+ def loading(&block)
+ trigger(:loading, true)
+ yield
+ trigger(:loading, false)
+ end
+
+ def format_event(name) #:nodoc:
+ name.is_a?(Array) ?
+ name.join('.') :
+ name.to_s
+ end
end
attr_reader :element
attr_reader :item
-
- def initialize(element, *args) #:nodoc:
- # jQuery element
- @element = element
- # Calling chain.js 'item' function
- @item = element.item()
- if @item
- # If possible, find Ruby object
- @item = self.class.find(@item._id.to_i)
- end
+
+ # Instance of an element on the view.
+ #
+ # item.destroy
+ # element.highlight.call
+ def initialize(id, *args) #:nodoc:
+ @element = self.class.bowline.element(
+ self.class.name, id
+ )
+ @item = self.class.find(id)
end
-
- # Trigger jQuery events on this element
- def trigger(event, data = nil)
- self.element.trigger(
- self.class.format_event(event),
- data
- )
- end
+
+ protected
+ # Trigger jQuery events on this element:
+ # trigger(:highlight)
+ def trigger(event, data = nil)
+ element.trigger(
+ self.class.format_event(event),
+ data
+ ).call
+ end
+
+ # Remove element from the view
+ def remove!
+ self.class.removed(item)
+ end
- # Raw DOM element
- def dom
- self.element[0]
- end
+ # Shortcut methods
- # Shortcut methods
+ # See self.class.js
+ def page
+ self.class.page
+ end
- # See self.class.show_view
- def show_view(*args)
- self.class.show_view(*args)
- end
-
- # See self.class.js
- def js
- self.class.js
- end
- alias :page :js
-
- # See self.class.jquery
- def jquery
- self.class.jquery
- end
-
- # See self.class.observer
- def observer
- self.class.observer
- end
+ # See self.class.jquery
+ def jquery
+ self.class.jquery
+ end
- # See self.class.logger
- def logger
- self.class.logger
- end
-
- private
- # This is just a unique identifier
- # for the item - and isn't
- # used in the dom
- def item_id
- if item.respond_to?(:dom_id)
- item.dom_id
- else
- [
- item.id,
- self.class.name.underscore
- ].join("_")
- end
+ # See self.class.logger
+ def logger
+ self.class.logger
end
end
end
end
\ No newline at end of file