require 'apotomo/event_handler'
module Apotomo
# Introduces event-processing functions into the StatefulWidget.
module EventMethods
extend ActiveSupport::Concern
included do
after_initialize :add_class_event_handlers
end
attr_writer :page_updates
def page_updates
@page_updates ||= []
end
def add_class_event_handlers(*)
self.class.responds_to_event_options.each { |options| respond_to_event(*options) }
end
module ClassMethods
def responds_to_event(*options)
responds_to_event_options << options
end
alias_method :respond_to_event, :responds_to_event
def responds_to_event_options
@responds_to_event_options ||= []
end
end
# Instructs the widget to look out for type Events that are passing by while bubbling.
# If an appropriate event is encountered the widget will send the targeted widget (or itself) to another
# state, which implies an update of the invoked widget.
#
# You may configure the event handler with the following options:
# :with => (optional) the state to invoke on the target widget, defaults to +type+.
# :on => (optional) the targeted widget's id, defaults to self.name
# :from => (optional) the source id of the widget that triggered the event, defaults to any widget
#
# Example:
#
# trap = widget(:trap, :charged, 'mouse_trap')
# trap.respond_to_event :mouseOver, :with => :catch_mouse
#
# This would instruct +trap+ to catch a :mouseOver event from any widget (including itself) and
# to invoke the state :catch_mouse on itself as trigger.
#
#
# hunter = widget(:form, :hunt_for_mice, 'my_form')
# hunter << widget(:input_field, :smell_like_cheese, 'mouse_trap')
# hunter << widget(:text_area, :stick_like_honey, 'bear_trap')
# hunter.respond_to_event :captured, :from => 'mouse_trap', :with => :refill_cheese, :on => 'mouse_trap'
#
# As both the bear- and the mouse trap can trigger a :captured event the later respond_to_event
# would invoke :refill_cheese on the mouse_trap widget as soon as this and only this widget fired.
# It is important to understand the :from parameter as it filters the event source - it wouldn't make
# sense to refill the mouse trap if the bear trap snapped, would it?
def respond_to_event(type, options={})
options.reverse_merge!( :once => true,
:with => type,
:on => self.name )
handler = InvokeEventHandler.new(:widget_id => options[:on], :state => options[:with])
return if options[:once] and event_table.all_handlers_for(type, options[:from]).include?(handler)
on(type, :do => handler, :from => options[:from])
end
# Fire an event of +type+ and let it bubble up. You may add arbitrary payload data to the event.
#
# Example:
#
# trigger(:dropped, :area => 59)
#
# which can be queried in a triggered state.
#
# def on_drop(event)
# if event.data[:area] == 59
def trigger(*args)
fire(*args)
end
protected
# Get all handlers from self for the passed event (overriding Onfire#local_event_handlers).
def local_event_handlers(event)
event_table.all_handlers_for(event.type, event.source.name) # we key with widget_id.
end
end
end