lib/apotomo/rails/controller_methods.rb in apotomo-1.0.5 vs lib/apotomo/rails/controller_methods.rb in apotomo-1.1.0.rc1

- old
+ new

@@ -1,152 +1,105 @@ require 'apotomo/request_processor' -require 'apotomo/rails/view_methods' - module Apotomo - module Rails - module ControllerMethods - include WidgetShortcuts - extend ActiveSupport::Concern +module Apotomo + module Rails + # Lazy-loads Apotomo support into controllers when needed. + module ControllerMethodsLoader + def has_widgets(*args, &block) + include ControllerMethods + has_widgets(*args, &block) + end + end + + + module ActionViewMethods + delegate :render_widget, :url_for_event, :to => :controller + end + + module ControllerMethods + include WidgetShortcuts + extend ActiveSupport::Concern + + included do + extend WidgetShortcuts - included do - extend WidgetShortcuts - - class_inheritable_array :has_widgets_blocks - self.has_widgets_blocks = [] - - helper ::Apotomo::Rails::ViewMethods - - after_filter :apotomo_freeze - end + class_inheritable_array :has_widgets_blocks + self.has_widgets_blocks = [] - module ClassMethods - # Yields the root widget to setup your widgets for a controller. The block is executed in - # controller _instance_ context, so you may use instance methods and variables of the - # controller. - # - # Example: - # class PostsController < ApplicationController - # has_widgets do |root| - # root << widget(:comments_widget, 'post-comments', :user => @current_user) - # end - def has_widgets(&block) - has_widgets_blocks << block - end - end - - def bound_use_widgets_blocks - session[:bound_use_widgets_blocks] ||= ProcHash.new - end - - def flush_bound_use_widgets_blocks - session[:bound_use_widgets_blocks] = nil - end - - def apotomo_request_processor - return @apotomo_request_processor if @apotomo_request_processor - - # happens once per request: - ### DISCUSS: policy in production? - options = { :flush_widgets => params[:flush_widgets], - :js_framework => Apotomo.js_framework || :prototype, - } ### TODO: process rails options (flush_tree, version) - - @apotomo_request_processor = Apotomo::RequestProcessor.new(self, session, options, self.class.has_widgets_blocks) - - flush_bound_use_widgets_blocks if @apotomo_request_processor.widgets_flushed? - - - @apotomo_request_processor - end - - def apotomo_root - apotomo_request_processor.root - end - - # Yields the root widget for manipulating the widget tree in a controller action. - # Note that the passed block is executed once per session and not in every request. + helper ActionViewMethods + end + + module ClassMethods + # Yields the root widget to setup your widgets for a controller. The block is executed in + # controller _instance_ context, so you may use instance methods and variables of the + # controller. # # Example: - # def login - # use_widgets do |root| - # root << widget(:login_widget, 'login_box') + # class PostsController < ApplicationController + # has_widgets do |root| + # root << widget(:comments_widget, 'post-comments', :user => @current_user) # end - # - # @box = render_widget 'login_box' - # end - def use_widgets(&block) - root = apotomo_root ### DISCUSS: let RequestProcessor initialize so we get flushed, eventually. maybe add a :before filter for that? or move #use_widgets to RequestProcessor? - - return if bound_use_widgets_blocks.include?(block) - - yield root - - bound_use_widgets_blocks << block # remember the proc. + def has_widgets(&block) + has_widgets_blocks << block end + end + + def apotomo_request_processor + return @apotomo_request_processor if @apotomo_request_processor + # happens once per request: + options = { :js_framework => Apotomo.js_framework || :prototype } # FIXME: remove :prototype - def render_widget(widget, options={}, &block) - apotomo_request_processor.render_widget_for(widget, options, &block) - end - - def apotomo_freeze - apotomo_request_processor.freeze! - end + @apotomo_request_processor = Apotomo::RequestProcessor.new(self, options, self.class.has_widgets_blocks) + end - def render_event_response - page_updates = apotomo_request_processor.process_for({:type => params[:type], :source => params[:source]}) - - return render_iframe_updates(page_updates) if params[:apotomo_iframe] - - render :text => apotomo_request_processor.render_page_updates(page_updates), :content_type => Mime::JS - end + def apotomo_root + apotomo_request_processor.root + end + + def render_widget(*args, &block) + apotomo_request_processor.render_widget_for(*args, &block) + end + + def render_event_response + page_updates = apotomo_request_processor.process_for(params) - # Returns the url to trigger a +type+ event from +:source+, which is a non-optional parameter. - # Additional +options+ will be appended to the query string. - # - # Note that this method will use the framework's internal routing if available (e.g. #url_for in Rails). - # - # Example: - # url_for_event(:paginate, :source => 'mouse', :page => 2) - # #=> http://apotomo.de/mouse/process_event_request?type=paginate&source=mouse&page=2 - def url_for_event(type, options) - options.reverse_merge!(:type => type) - - apotomo_event_path(apotomo_request_processor.address_for(options)) - end + return render_iframe_updates(page_updates) if params[:apotomo_iframe] - protected + render :text => page_updates.join("\n"), :content_type => Mime::JS + end + + # Returns the url to trigger a +type+ event from +:source+, which is a non-optional parameter. + # Additional +options+ will be appended to the query string. + # + # Note that this method will use the framework's internal routing if available (e.g. #url_for in Rails). + # + # Example: + # url_for_event(:paginate, :source => 'mouse', :page => 2) + # #=> http://apotomo.de/mouse/process_event_request?type=paginate&source=mouse&page=2 + def url_for_event(type, options) + options.reverse_merge!(:type => type) - def parent_controller - self - end + apotomo_event_path(apotomo_request_processor.address_for(options)) + end + + protected + + # TODO: remove me! only needed in widget_shortcuts. + def parent_controller + self + end + + + # Renders the page updates through an iframe. Copied from responds_to_parent, + # see http://github.com/markcatley/responds_to_parent . + def render_iframe_updates(page_updates) + escaped_script = Apotomo::JavascriptGenerator.escape(page_updates.join("\n")) - - - # Renders the page updates through an iframe. Copied from responds_to_parent, - # see http://github.com/markcatley/responds_to_parent . - def render_iframe_updates(page_updates) - script = apotomo_request_processor.render_page_updates(page_updates) - escaped_script = Apotomo::JavascriptGenerator.escape(script) - - render :text => "<html><body><script type='text/javascript' charset='utf-8'> + render :text => "<html><body><script type='text/javascript' charset='utf-8'> var loc = document.location; with(window.parent) { setTimeout(function() { window.eval('#{escaped_script}'); window.loc && loc.replace('about:blank'); }, 1) } </script></body></html>", :content_type => 'text/html' - end - - class ProcHash < Array - def id_for_proc(proc) - proc.to_s.split('@').last - end - - def <<(proc) - super(id_for_proc(proc)) - end - - def include?(proc) - super(id_for_proc(proc)) - end end end end end