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