winton-rails_widget 1.0.2 → 1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +20 -5
- data/lib/rails_widget.rb +99 -3
- data/lib/rails_widget/assets.rb +196 -86
- data/lib/rails_widget/widget.rb +148 -227
- data/lib/rails_widget/widgets.rb +188 -0
- metadata +6 -6
- data/tasks/rails_widget.rake +0 -31
    
        data/README.markdown
    CHANGED
    
    | @@ -1,8 +1,23 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 1 | 
            +
            RailsWidget
         | 
| 2 | 
            +
            ===========
         | 
| 3 3 |  | 
| 4 | 
            -
             | 
| 4 | 
            +
            Allows you to group your client-side assets into distributable "widgets"
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 6 | 
            +
            * Attach assets and render partials with a single <tt>widget</tt> call
         | 
| 7 | 
            +
            * Configure widgets via an <tt>options.rb</tt> file
         | 
| 8 | 
            +
            * Supported assets: flash, images, partials, javascripts, stylesheets, and textarea templates
         | 
| 7 9 |  | 
| 8 | 
            -
             | 
| 10 | 
            +
             | 
| 11 | 
            +
            Install
         | 
| 12 | 
            +
            -------
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            	script/plugin install git://github.com/winton/rails_widget.git
         | 
| 15 | 
            +
             | 
| 16 | 
            +
             | 
| 17 | 
            +
            Documentation
         | 
| 18 | 
            +
            --------------
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            [RDoc](http://wintoni.us/rails_widget) for more details.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
             | 
| 23 | 
            +
            ##### Copyright © 2008 [Winton Welsh](mailto:mail@wintoni.us), released under the MIT license
         | 
    
        data/lib/rails_widget.rb
    CHANGED
    
    | @@ -1,7 +1,103 @@ | |
| 1 | 
            +
            # RailsWidget allows you to group your client-side assets into distributable "widgets"
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # * Attach assets and render partials with a single <tt>widget</tt> call
         | 
| 4 | 
            +
            # * Configure widgets via an <tt>options.rb</tt> file
         | 
| 5 | 
            +
            # * Supports flash, images, javascripts, partials, stylesheets, and textarea templates
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            # == Example
         | 
| 8 | 
            +
            # === What is a widget?
         | 
| 9 | 
            +
            # Each directory in <tt>app/widgets</tt> is considered a widget. Let's make a widget called <tt>alert</tt>.
         | 
| 10 | 
            +
            #
         | 
| 11 | 
            +
            #   app/
         | 
| 12 | 
            +
            #     widgets/
         | 
| 13 | 
            +
            #       alert/
         | 
| 14 | 
            +
            #         options.rb
         | 
| 15 | 
            +
            #         flash/
         | 
| 16 | 
            +
            #         images/
         | 
| 17 | 
            +
            #         javascripts/
         | 
| 18 | 
            +
            #           alert.js
         | 
| 19 | 
            +
            #           init.js
         | 
| 20 | 
            +
            #         partials/
         | 
| 21 | 
            +
            #           _init.html.erb
         | 
| 22 | 
            +
            #         stylesheets/
         | 
| 23 | 
            +
            #           init.css
         | 
| 24 | 
            +
            #           style.css
         | 
| 25 | 
            +
            #         templates/
         | 
| 26 | 
            +
            #
         | 
| 27 | 
            +
            # <b>Init</b> files are rendered directly into the layout (inline, dynamically generated).
         | 
| 28 | 
            +
            #
         | 
| 29 | 
            +
            # ==== options.rb
         | 
| 30 | 
            +
            #   { :id => 'alert', :message => 'Hello world!', :color => 'red' }
         | 
| 31 | 
            +
            #
         | 
| 32 | 
            +
            # ==== javascripts/alert.js
         | 
| 33 | 
            +
            #   function alertWidget(options) {
         | 
| 34 | 
            +
            #     alert(options.message);
         | 
| 35 | 
            +
            #   }
         | 
| 36 | 
            +
            #
         | 
| 37 | 
            +
            # ==== javascripts/init.js
         | 
| 38 | 
            +
            #   alertWidget(<%= options.to_json %>);
         | 
| 39 | 
            +
            #
         | 
| 40 | 
            +
            #
         | 
| 41 | 
            +
            # ==== partials/_init.html.erb
         | 
| 42 | 
            +
            #   <div id="<%= id %>" class="alert">
         | 
| 43 | 
            +
            #     You just got alerted.
         | 
| 44 | 
            +
            #   </div>
         | 
| 45 | 
            +
            #
         | 
| 46 | 
            +
            # ==== stylesheets/init.css
         | 
| 47 | 
            +
            #   #<%= id %> { color:<%= color %>; }
         | 
| 48 | 
            +
            #
         | 
| 49 | 
            +
            # ==== stylesheets/style.css
         | 
| 50 | 
            +
            #   .alert { font-size:18px; }
         | 
| 51 | 
            +
            #
         | 
| 52 | 
            +
            # === Layout view
         | 
| 53 | 
            +
            #   <html>
         | 
| 54 | 
            +
            #     <head>
         | 
| 55 | 
            +
            #       <%= javascripts %>
         | 
| 56 | 
            +
            #       <%= stylesheets %>
         | 
| 57 | 
            +
            #     </head>
         | 
| 58 | 
            +
            #     <body>
         | 
| 59 | 
            +
            #       <%= yield %>
         | 
| 60 | 
            +
            #     </body>
         | 
| 61 | 
            +
            #   </html>
         | 
| 62 | 
            +
            #
         | 
| 63 | 
            +
            # === Action view
         | 
| 64 | 
            +
            #   <%= widget :alert, :id => 'alert1', :color => 'blue' %>
         | 
| 65 | 
            +
            #   <%= widget :alert, :id => 'alert2' %>
         | 
| 66 | 
            +
            #
         | 
| 67 | 
            +
            # === Resulting HTML
         | 
| 68 | 
            +
            #   <html>
         | 
| 69 | 
            +
            #     <head>
         | 
| 70 | 
            +
            #       <script src="/javascripts/widgets/alert/alert.js?1220593492" type="text/javascript"></script>
         | 
| 71 | 
            +
            #       <script type='text/javascript'>
         | 
| 72 | 
            +
            #         alertWidget({ id: 'alert', message: 'Hello world!', color: 'red' });
         | 
| 73 | 
            +
            #       </script>
         | 
| 74 | 
            +
            #       <link href="/stylesheets/widgets/alert/style.css?1220593492" media="screen" rel="stylesheet" type="text/css" />
         | 
| 75 | 
            +
            #       <style type="text/css">
         | 
| 76 | 
            +
            #         #alert1 { color:blue; }
         | 
| 77 | 
            +
            #         #alert2 { color:red; }
         | 
| 78 | 
            +
            #       </style>
         | 
| 79 | 
            +
            #     </head>
         | 
| 80 | 
            +
            #     <body>
         | 
| 81 | 
            +
            #       <div id="alert1" class="alert">
         | 
| 82 | 
            +
            #         You just got alerted.
         | 
| 83 | 
            +
            #       </div>
         | 
| 84 | 
            +
            #       <div id="alert2" class="alert">
         | 
| 85 | 
            +
            #         You just got alerted.
         | 
| 86 | 
            +
            #       </div>
         | 
| 87 | 
            +
            #     </body>
         | 
| 88 | 
            +
            #   </html>
         | 
| 89 | 
            +
            #
         | 
| 90 | 
            +
            # == Inheritance
         | 
| 91 | 
            +
            #
         | 
| 92 | 
            +
            module RailsWidget
         | 
| 93 | 
            +
            end
         | 
| 94 | 
            +
             | 
| 1 95 | 
             
            Dir[File.expand_path('*/*.rb', File.dirname(__FILE__))].each do |f|
         | 
| 2 96 | 
             
              require [ File.dirname(f), File.basename(f, '.rb') ].join('/')
         | 
| 3 97 | 
             
            end
         | 
| 4 98 |  | 
| 5 | 
            -
            ActionView::Base.send :include,  | 
| 6 | 
            -
            ActionController::Base.send :include,  | 
| 7 | 
            -
            ActionController::Base.view_paths += [ RAILS_ROOT + '/app/widgets' ]
         | 
| 99 | 
            +
            ActionView::Base.send :include, RailsWidget
         | 
| 100 | 
            +
            ActionController::Base.send :include, RailsWidget
         | 
| 101 | 
            +
            ActionController::Base.view_paths += [ RAILS_ROOT + '/app/widgets' ]
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            # :main:RailsWidget
         | 
    
        data/lib/rails_widget/assets.rb
    CHANGED
    
    | @@ -1,114 +1,224 @@ | |
| 1 | 
            -
            module  | 
| 2 | 
            -
              
         | 
| 3 | 
            -
              def default_javascript
         | 
| 4 | 
            -
                "#{params[:controller]}/#{params[:action]}"
         | 
| 5 | 
            -
              end
         | 
| 6 | 
            -
              
         | 
| 7 | 
            -
              def default_stylesheet
         | 
| 8 | 
            -
                "#{params[:controller]}/#{params[:action]}"
         | 
| 9 | 
            -
              end
         | 
| 1 | 
            +
            module RailsWidget
         | 
| 10 2 |  | 
| 3 | 
            +
              # Adds or renders javascript assets based on whether parameters are given or not.
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              # ==== Layout view
         | 
| 6 | 
            +
              #   <html>
         | 
| 7 | 
            +
              #     <head>
         | 
| 8 | 
            +
              #       <%= javascripts %>
         | 
| 9 | 
            +
              #     </head>
         | 
| 10 | 
            +
              #     <%= yield %>
         | 
| 11 | 
            +
              #   </html>
         | 
| 12 | 
            +
              #
         | 
| 13 | 
            +
              # ==== Action view
         | 
| 14 | 
            +
              #   <% javascripts 'script1', 'script2' do -%>
         | 
| 15 | 
            +
              #     alert('Hello world!');
         | 
| 16 | 
            +
              #   <% end -%>
         | 
| 17 | 
            +
              #   Content goes here.
         | 
| 18 | 
            +
              #
         | 
| 19 | 
            +
              # ==== Resulting HTML
         | 
| 20 | 
            +
              #   <html>
         | 
| 21 | 
            +
              #     <head>
         | 
| 22 | 
            +
              #       <script src="/javascripts/script1.js?1220593492" type="text/javascript"></script>
         | 
| 23 | 
            +
              #       <script src="/javascripts/script2.js?1220593492" type="text/javascript"></script>
         | 
| 24 | 
            +
              #       <script type='text/javascript'>
         | 
| 25 | 
            +
              #         alert('Hello world!');
         | 
| 26 | 
            +
              #       </script>
         | 
| 27 | 
            +
              #     </head>
         | 
| 28 | 
            +
              #     Content goes here.
         | 
| 29 | 
            +
              #   </html>
         | 
| 30 | 
            +
              #
         | 
| 31 | 
            +
              # Calling <tt>javascripts</tt> with path parameters or a script block will store the asset for later rendering.
         | 
| 32 | 
            +
              #
         | 
| 33 | 
            +
              # Calling <tt>javascripts</tt> without parameters renders the assets in the order they were added.
         | 
| 34 | 
            +
              #
         | 
| 35 | 
            +
              # The method accepts all options supported by <tt>javascript_include_tag</tt>.
         | 
| 36 | 
            +
              #
         | 
| 11 37 | 
             
              def javascripts(*paths, &block)
         | 
| 12 | 
            -
                 | 
| 38 | 
            +
                @assets ||= Assets.new binding, controller, logger
         | 
| 39 | 
            +
                @assets.javascripts *paths, &block
         | 
| 13 40 | 
             
              end
         | 
| 14 41 |  | 
| 42 | 
            +
              # Adds or renders stylesheet assets based on whether parameters are given or not.
         | 
| 43 | 
            +
              #
         | 
| 44 | 
            +
              # ==== Layout example
         | 
| 45 | 
            +
              #   <html>
         | 
| 46 | 
            +
              #     <head>
         | 
| 47 | 
            +
              #       <%= stylesheets %>
         | 
| 48 | 
            +
              #     </head>
         | 
| 49 | 
            +
              #     <%= yield %>
         | 
| 50 | 
            +
              #   </html>
         | 
| 51 | 
            +
              #
         | 
| 52 | 
            +
              # ==== Action example
         | 
| 53 | 
            +
              #   <% stylesheets 'style1', 'style2' -%>
         | 
| 54 | 
            +
              #   Content goes here.
         | 
| 55 | 
            +
              #
         | 
| 56 | 
            +
              # ==== Result
         | 
| 57 | 
            +
              #   <html>
         | 
| 58 | 
            +
              #     <head>
         | 
| 59 | 
            +
              #       <link href="/stylesheets/style1.css?1224923418" media="screen" rel="stylesheet" type="text/css" />
         | 
| 60 | 
            +
              #       <link href="/stylesheets/style2.css?1224923418" media="screen" rel="stylesheet" type="text/css" />
         | 
| 61 | 
            +
              #     </head>
         | 
| 62 | 
            +
              #     Content goes here.
         | 
| 63 | 
            +
              #   </html>
         | 
| 64 | 
            +
              #
         | 
| 65 | 
            +
              # Calling <tt>stylesheets</tt> with path parameters will store the asset for later rendering.
         | 
| 66 | 
            +
              #
         | 
| 67 | 
            +
              # Calling <tt>stylesheets</tt> without parameters renders the assets in the order they were added.
         | 
| 68 | 
            +
              #
         | 
| 69 | 
            +
              # The method accepts all options supported by <tt>stylesheet_link_tag</tt>.
         | 
| 70 | 
            +
              #
         | 
| 15 71 | 
             
              def stylesheets(*paths, &block)
         | 
| 16 | 
            -
                 | 
| 72 | 
            +
                @assets ||= Assets.new binding, controller, logger
         | 
| 73 | 
            +
                @assets.stylesheets *paths, &block
         | 
| 17 74 | 
             
              end
         | 
| 18 75 |  | 
| 19 | 
            -
               | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
               | 
| 25 | 
            -
              
         | 
| 26 | 
            -
               | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 76 | 
            +
              # Adds or renders textarea-based templates based on whether parameters are given or not.
         | 
| 77 | 
            +
              #
         | 
| 78 | 
            +
              # Use this with something like PURE <http://beebole.com/pure> or TrimPath's JST <http://trimpath.com>.
         | 
| 79 | 
            +
              #
         | 
| 80 | 
            +
              # ==== Layout example
         | 
| 81 | 
            +
              #   <html>
         | 
| 82 | 
            +
              #     <%= yield %>
         | 
| 83 | 
            +
              #     <%= templates %>
         | 
| 84 | 
            +
              #   </html>
         | 
| 85 | 
            +
              #
         | 
| 86 | 
            +
              # ==== Action example
         | 
| 87 | 
            +
              #   <% templates :id => 'myid', :partial => 'some_action/partial', :locals => { :x => 'Hello world' } -%>
         | 
| 88 | 
            +
              #   <% templates do -%>
         | 
| 89 | 
            +
              #     Template goes here.
         | 
| 90 | 
            +
              #   <% end -%>
         | 
| 91 | 
            +
              #   Content goes here.
         | 
| 92 | 
            +
              #
         | 
| 93 | 
            +
              # ==== Partial example (<tt>some_action/partial</tt>)
         | 
| 94 | 
            +
              #   <%= x %>!
         | 
| 95 | 
            +
              #
         | 
| 96 | 
            +
              # ==== Result
         | 
| 97 | 
            +
              #   <html>
         | 
| 98 | 
            +
              #     Content goes here.
         | 
| 99 | 
            +
              #     <textarea id='template_myid' style='display:none'>
         | 
| 100 | 
            +
              #       Hello world!
         | 
| 101 | 
            +
              #     </textarea>
         | 
| 102 | 
            +
              #     <textarea id='template' style='display:none'>
         | 
| 103 | 
            +
              #       Template goes here.
         | 
| 104 | 
            +
              #     </textarea>
         | 
| 105 | 
            +
              #   </html>
         | 
| 106 | 
            +
              #
         | 
| 107 | 
            +
              # Calling <tt>templates</tt> with path parameters or a block will store the asset for later rendering.
         | 
| 108 | 
            +
              #
         | 
| 109 | 
            +
              # Calling <tt>templates</tt> without parameters renders the assets in the order they were added.
         | 
| 110 | 
            +
              #
         | 
| 111 | 
            +
              def templates(*options, &block)
         | 
| 112 | 
            +
                @assets ||= Assets.new binding, controller, logger
         | 
| 113 | 
            +
                @assets.templates *options, &block
         | 
| 31 114 | 
             
              end
         | 
| 32 115 |  | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
              def add_assets(type, paths, &block)
         | 
| 36 | 
            -
                options = paths.extract_options!
         | 
| 37 | 
            -
                paths.flatten! unless type == :templates
         | 
| 116 | 
            +
              class Assets
         | 
| 117 | 
            +
                attr :assets, true
         | 
| 38 118 |  | 
| 39 | 
            -
                 | 
| 40 | 
            -
                 | 
| 41 | 
            -
                 | 
| 42 | 
            -
                 | 
| 119 | 
            +
                # Used for eval access
         | 
| 120 | 
            +
                attr :block,   true
         | 
| 121 | 
            +
                attr :params,  true
         | 
| 122 | 
            +
                attr :options, true
         | 
| 43 123 |  | 
| 44 | 
            -
                 | 
| 124 | 
            +
                def initialize(bind, controller, logger)
         | 
| 125 | 
            +
                  @assets = {}
         | 
| 126 | 
            +
                  @bind = bind
         | 
| 127 | 
            +
                  @controller = controller
         | 
| 128 | 
            +
                  @logger = logger
         | 
| 129 | 
            +
                end
         | 
| 45 130 |  | 
| 46 | 
            -
                 | 
| 47 | 
            -
                   | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 131 | 
            +
                def javascripts(*params, &block)
         | 
| 132 | 
            +
                  add_assets :javascripts, params, &block
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
              
         | 
| 135 | 
            +
                def stylesheets(*params, &block)
         | 
| 136 | 
            +
                  add_assets :stylesheets, params, &block
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
              
         | 
| 139 | 
            +
                def templates(*params, &block)
         | 
| 140 | 
            +
                  add_assets :templates, params, &block
         | 
| 55 141 | 
             
                end
         | 
| 56 142 |  | 
| 57 | 
            -
                 | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
                   | 
| 61 | 
            -
                  
         | 
| 62 | 
            -
                   | 
| 63 | 
            -
                  
         | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 143 | 
            +
                private
         | 
| 144 | 
            +
                
         | 
| 145 | 
            +
                def add_assets(type, params, &block)
         | 
| 146 | 
            +
                  options = params.extract_options! unless type == :templates
         | 
| 147 | 
            +
                  capture = block_to_string &block
         | 
| 148 | 
            +
                  asset   = delete_if_empty(:options => options, :params => params, :capture => capture)
         | 
| 149 | 
            +
                  if asset.empty?
         | 
| 150 | 
            +
                    remove_dups :javascripts, :params
         | 
| 151 | 
            +
                    remove_dups :stylesheets, :params, :capture
         | 
| 152 | 
            +
                    remove_dups :templates,   :params, :capture
         | 
| 153 | 
            +
                    captures = []
         | 
| 154 | 
            +
                    tags     = []
         | 
| 155 | 
            +
                    @assets[type].each do |item|
         | 
| 156 | 
            +
                      @capture = item[:capture]
         | 
| 157 | 
            +
                      @params  = item[:params]
         | 
| 72 158 | 
             
                      case type
         | 
| 73 159 | 
             
                      when :javascripts
         | 
| 74 | 
            -
                         | 
| 160 | 
            +
                        captures.push(@capture) if @capture
         | 
| 161 | 
            +
                        tags.push(eval("javascript_include_tag *[ @assets.params, @assets.options ].flatten.compact", @bind)) if @params
         | 
| 75 162 | 
             
                      when :stylesheets
         | 
| 76 | 
            -
                         | 
| 163 | 
            +
                        captures.push(@capture) if @capture
         | 
| 164 | 
            +
                        tags.push(eval("stylesheet_link_tag    *[ @assets.params, @assets.options ].flatten.compact", @bind)) if @params
         | 
| 77 165 | 
             
                      when :templates
         | 
| 78 | 
            -
                        textarea_template  | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
                      when :javascripts
         | 
| 83 | 
            -
                        js.push(item) unless item.blank?
         | 
| 84 | 
            -
                        nil
         | 
| 85 | 
            -
                      else
         | 
| 86 | 
            -
                        item
         | 
| 166 | 
            +
                        captures.push(textarea_template(@params.pop.merge(:body => @capture))) if @capture
         | 
| 167 | 
            +
                        @params.each do |options|
         | 
| 168 | 
            +
                          captures << textarea_template(options)
         | 
| 169 | 
            +
                        end
         | 
| 87 170 | 
             
                      end
         | 
| 88 171 | 
             
                    end
         | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 172 | 
            +
                    case type
         | 
| 173 | 
            +
                    when :javascripts
         | 
| 174 | 
            +
                      tags.join("\n") + "\n<script type='text/javascript'>\n#{captures.join "\n"}\n</script>"
         | 
| 175 | 
            +
                    when :stylesheets
         | 
| 176 | 
            +
                      tags.join("\n") + "\n<style type='text/css'>\n#{captures.join "\n"}\n</style>"
         | 
| 177 | 
            +
                    when :templates
         | 
| 178 | 
            +
                      captures.uniq.join "\n"
         | 
| 179 | 
            +
                    end
         | 
| 92 180 | 
             
                  else
         | 
| 93 | 
            -
                    assets | 
| 181 | 
            +
                    @assets[type] ||= []
         | 
| 182 | 
            +
                    @assets[type].push asset
         | 
| 94 183 | 
             
                  end
         | 
| 95 184 | 
             
                end
         | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
                   | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
                   | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 185 | 
            +
                
         | 
| 186 | 
            +
                def block_to_string(&block)
         | 
| 187 | 
            +
                  return nil unless block
         | 
| 188 | 
            +
                  @block = block
         | 
| 189 | 
            +
                  eval "capture(&@assets.block)", @bind
         | 
| 190 | 
            +
                end
         | 
| 191 | 
            +
                
         | 
| 192 | 
            +
                def delete_if_empty(hash)
         | 
| 193 | 
            +
                  list = []
         | 
| 194 | 
            +
                  hash.each { |key, value| list.push(key) if !value || value.empty? || value.blank? }
         | 
| 195 | 
            +
                  list.each { |key|        hash.delete key }
         | 
| 196 | 
            +
                  hash
         | 
| 197 | 
            +
                end
         | 
| 198 | 
            +
                
         | 
| 199 | 
            +
                def remove_dups(asset_type, *types)
         | 
| 200 | 
            +
                  asset = @assets[asset_type]
         | 
| 201 | 
            +
                  types.each do |type|
         | 
| 202 | 
            +
                    list = []
         | 
| 203 | 
            +
                    asset.each do |a|
         | 
| 204 | 
            +
                      if list.include?(a[type])
         | 
| 205 | 
            +
                        a.delete type
         | 
| 206 | 
            +
                      else
         | 
| 207 | 
            +
                        list << a[type]
         | 
| 208 | 
            +
                      end
         | 
| 109 209 | 
             
                    end
         | 
| 210 | 
            +
                  end if asset
         | 
| 211 | 
            +
                end
         | 
| 212 | 
            +
                
         | 
| 213 | 
            +
                def textarea_template(options)
         | 
| 214 | 
            +
                  id = 'template' + (options[:id] ? "_#{options[:id]}" : '')
         | 
| 215 | 
            +
                  if options[:body]
         | 
| 216 | 
            +
                    body = options[:body]
         | 
| 217 | 
            +
                  elsif options[:partial]
         | 
| 218 | 
            +
                    body = @controller.render_to_string :partial => options[:partial], :locals => options[:locals]
         | 
| 110 219 | 
             
                  end
         | 
| 220 | 
            +
                  return nil unless body
         | 
| 221 | 
            +
                  "<textarea id='#{id}' style='display:none'>\n#{body}\n</textarea>" 
         | 
| 111 222 | 
             
                end
         | 
| 112 223 | 
             
              end
         | 
| 113 | 
            -
              
         | 
| 114 224 | 
             
            end
         | 
    
        data/lib/rails_widget/widget.rb
    CHANGED
    
    | @@ -1,248 +1,169 @@ | |
| 1 | 
            -
            module  | 
| 1 | 
            +
            module RailsWidget
         | 
| 2 2 |  | 
| 3 | 
            -
               | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
                 | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
                 | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
                   | 
| 18 | 
            -
                    javascripts *(@layout_happened ? [ :layout => true ] : []) do
         | 
| 19 | 
            -
                      js
         | 
| 20 | 
            -
                    end
         | 
| 21 | 
            -
                    partial
         | 
| 22 | 
            -
                  end
         | 
| 23 | 
            -
                end
         | 
| 24 | 
            -
              end
         | 
| 25 | 
            -
              
         | 
| 26 | 
            -
              def require_widget(*path)
         | 
| 27 | 
            -
                widgets, options = widget_instances path
         | 
| 28 | 
            -
                widgets.each do |w|
         | 
| 29 | 
            -
                  w.copy_assets
         | 
| 30 | 
            -
                  js  = w.helper_targets :javascripts
         | 
| 31 | 
            -
                  css = w.helper_targets :stylesheets
         | 
| 32 | 
            -
                  javascripts *(js  + [ :cache => w.cache, :layout => @layout_happened ]) unless js.empty?
         | 
| 33 | 
            -
                  stylesheets *(css + [ :cache => w.cache, :layout => @layout_happened ]) unless css.empty?
         | 
| 34 | 
            -
                  templates   *(w.assets[:templates].collect do |t|
         | 
| 35 | 
            -
                    [ File.basename(t), t, options.merge(:options => options) ]
         | 
| 36 | 
            -
                  end) unless w.assets[:templates].empty?
         | 
| 37 | 
            -
                end
         | 
| 38 | 
            -
              end
         | 
| 39 | 
            -
              
         | 
| 40 | 
            -
              def widget_flash_path(*path)
         | 
| 41 | 
            -
                flash = path.pop
         | 
| 42 | 
            -
                "/flash/widgets/#{path.join('/')}/#{flash}"
         | 
| 43 | 
            -
              end
         | 
| 44 | 
            -
              
         | 
| 45 | 
            -
              def widget_image(*path)
         | 
| 46 | 
            -
                options = path.extract_options!
         | 
| 47 | 
            -
                image = path.pop
         | 
| 48 | 
            -
                image_tag "widgets/#{path.join('/')}/#{image}", options
         | 
| 49 | 
            -
              end
         | 
| 50 | 
            -
              
         | 
| 51 | 
            -
              def widget_image_path(*path)
         | 
| 52 | 
            -
                image = path.pop
         | 
| 53 | 
            -
                "/images/widgets/#{path.join('/')}/#{image}"
         | 
| 54 | 
            -
              end
         | 
| 55 | 
            -
              
         | 
| 56 | 
            -
              def widget_partial(*path)
         | 
| 57 | 
            -
                options = path.extract_options!
         | 
| 58 | 
            -
                partial = path.pop
         | 
| 59 | 
            -
                path << options
         | 
| 60 | 
            -
                widgets, options = widget_instances path
         | 
| 61 | 
            -
                options = {
         | 
| 62 | 
            -
                  :locals  => options.merge(:options => options),
         | 
| 63 | 
            -
                  :partial => "#{path.join('/')}/partials/#{partial}"
         | 
| 64 | 
            -
                }
         | 
| 65 | 
            -
                render options
         | 
| 66 | 
            -
              end
         | 
| 67 | 
            -
              
         | 
| 68 | 
            -
              def widget_instances(path)
         | 
| 69 | 
            -
                @widgets ||= Widgets.new binding, controller, logger
         | 
| 70 | 
            -
                options = path.extract_options!
         | 
| 71 | 
            -
                @widgets.build path, options
         | 
| 72 | 
            -
              end
         | 
| 73 | 
            -
              
         | 
| 74 | 
            -
              class Widgets
         | 
| 75 | 
            -
                attr :widgets, true
         | 
| 76 | 
            -
                
         | 
| 77 | 
            -
                def initialize(bind, controller, logger)
         | 
| 78 | 
            -
                  @bind       = bind
         | 
| 3 | 
            +
              # Stores information about a widget and renders assets to <tt>public/</tt> when necessary.
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              class Widget
         | 
| 6 | 
            +
                attr :assets,  true # Paths for each ASSET_TYPE
         | 
| 7 | 
            +
                attr :cache,   true # Cache path for Rails asset helpers
         | 
| 8 | 
            +
                attr :options, true # Options hash from options.rb
         | 
| 9 | 
            +
                attr :path,    true # Path to widget
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                ASSET_TYPES = [ :flash, :images, :javascripts, :stylesheets, :templates, :init_css, :init_js, :init_partials ]
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                # Calls <tt>update_options</tt> and <tt>update_asset</tt> for each <tt>ASSET_TYPE</tt>.
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                def initialize(path, bind, controller, logger)
         | 
| 16 | 
            +
                  @path = path
         | 
| 17 | 
            +
                  @bind = bind
         | 
| 79 18 | 
             
                  @controller = controller
         | 
| 80 | 
            -
                  @logger | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
                   | 
| 86 | 
            -
             | 
| 87 | 
            -
                   | 
| 88 | 
            -
             | 
| 89 | 
            -
                     | 
| 90 | 
            -
                    @widgets[r]
         | 
| 19 | 
            +
                  @logger = logger
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  @assets = {}
         | 
| 22 | 
            +
                  @options  = {}
         | 
| 23 | 
            +
                  @rendered = {}
         | 
| 24 | 
            +
                  @targeted = {}
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  update_options
         | 
| 27 | 
            +
                  ASSET_TYPES.each do |type|
         | 
| 28 | 
            +
                    update_asset type
         | 
| 91 29 | 
             
                  end
         | 
| 92 | 
            -
                  [ widgets, opts.merge(options) ]
         | 
| 93 30 | 
             
                end
         | 
| 94 31 |  | 
| 95 | 
            -
                 | 
| 96 | 
            -
                
         | 
| 97 | 
            -
                def  | 
| 98 | 
            -
                   | 
| 99 | 
            -
                  last = paths.length - 1
         | 
| 100 | 
            -
                  paths.each_index do |x|
         | 
| 101 | 
            -
                    if x != 0 && File.exists?("app/widgets/#{paths[x]}")
         | 
| 102 | 
            -
                      ordered << related_paths(paths[x..last])
         | 
| 103 | 
            -
                    end
         | 
| 104 | 
            -
                    path = paths[0..x].join '/'
         | 
| 105 | 
            -
                    if File.exists?("app/widgets/#{path}")
         | 
| 106 | 
            -
                      ordered << path
         | 
| 107 | 
            -
                    end
         | 
| 108 | 
            -
                  end
         | 
| 109 | 
            -
                  ordered.flatten
         | 
| 32 | 
            +
                # Returns a cache path suitable for Rails asset helpers.
         | 
| 33 | 
            +
                #
         | 
| 34 | 
            +
                def cache
         | 
| 35 | 
            +
                  'cache/' + (@path.empty? ? 'base' : @path.gsub('/', '_'))
         | 
| 110 36 | 
             
                end
         | 
| 111 | 
            -
             | 
| 112 | 
            -
                 | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
             | 
| 122 | 
            -
                     | 
| 123 | 
            -
                     | 
| 124 | 
            -
             | 
| 125 | 
            -
             | 
| 126 | 
            -
             | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
                    @assets.each do |key, value|
         | 
| 138 | 
            -
                      from, to = to_path key
         | 
| 139 | 
            -
                      value.each do |asset|
         | 
| 140 | 
            -
                        base = File.basename asset
         | 
| 141 | 
            -
                        f = [ from, base ].join '/'
         | 
| 142 | 
            -
                        t = [ to,   base ].join '/'
         | 
| 143 | 
            -
                        t.gsub!('/stylesheets/', '/stylesheets/sass/') if t.include?('.sass')
         | 
| 144 | 
            -
                        next unless needs_update?(f, t)
         | 
| 145 | 
            -
                        case key
         | 
| 146 | 
            -
                        when :flash, :images
         | 
| 147 | 
            -
                          FileUtils.mkdir_p to
         | 
| 148 | 
            -
                          FileUtils.copy f, t
         | 
| 149 | 
            -
                        when :javascripts, :stylesheets
         | 
| 150 | 
            -
                          FileUtils.mkdir_p File.dirname(t)
         | 
| 151 | 
            -
                          File.open t, 'w' do |file|
         | 
| 152 | 
            -
                            file.write @controller.render_to_string(:file => f, :locals => @options.merge(:options => @options))
         | 
| 153 | 
            -
                          end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                # Copies widget images to <tt>public/images/widgets</tt>.
         | 
| 39 | 
            +
                #
         | 
| 40 | 
            +
                # Copies widget flash files to <tt>public/flash/widgets</tt>.
         | 
| 41 | 
            +
                #
         | 
| 42 | 
            +
                # Renders javascripts to <tt>public/javascripts/widgets</tt>.
         | 
| 43 | 
            +
                #
         | 
| 44 | 
            +
                # Renders stylesheets to <tt>public/stylesheets/widgets</tt>.
         | 
| 45 | 
            +
                #
         | 
| 46 | 
            +
                def copy_assets
         | 
| 47 | 
            +
                  @assets.each do |key, value|
         | 
| 48 | 
            +
                    from, to = to_path key
         | 
| 49 | 
            +
                    value.each do |asset|
         | 
| 50 | 
            +
                      base = File.basename asset
         | 
| 51 | 
            +
                      f = [ from, base ].join '/'
         | 
| 52 | 
            +
                      t = [ to,   base ].join '/'
         | 
| 53 | 
            +
                      t.gsub!('/stylesheets/', '/stylesheets/sass/') if t.include?('.sass')
         | 
| 54 | 
            +
                      next unless needs_update?(f, t)
         | 
| 55 | 
            +
                      case key
         | 
| 56 | 
            +
                      when :flash, :images
         | 
| 57 | 
            +
                        FileUtils.mkdir_p to
         | 
| 58 | 
            +
                        FileUtils.cp_r f, t
         | 
| 59 | 
            +
                      when :javascripts, :stylesheets
         | 
| 60 | 
            +
                        FileUtils.mkdir_p File.dirname(t)
         | 
| 61 | 
            +
                        File.open t, 'w' do |file|
         | 
| 62 | 
            +
                          file.write @controller.render_to_string(:file => f, :locals => @options.merge(:options => @options))
         | 
| 154 63 | 
             
                        end
         | 
| 155 64 | 
             
                      end
         | 
| 156 65 | 
             
                    end
         | 
| 157 66 | 
             
                  end
         | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
                      end
         | 
| 174 | 
            -
                    else @assets[type]
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
                
         | 
| 69 | 
            +
                # Returns asset paths to be included via the Assets helpers for a particular <tt>ASSET_TYPE</tt>.
         | 
| 70 | 
            +
                #
         | 
| 71 | 
            +
                # See <tt>add_static_assets (Widgets)</tt>.
         | 
| 72 | 
            +
                #
         | 
| 73 | 
            +
                def asset_paths(type)
         | 
| 74 | 
            +
                  return [] if @targeted[type]
         | 
| 75 | 
            +
                  @targeted[type] = true
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  from, to = to_path type
         | 
| 78 | 
            +
                  case type
         | 
| 79 | 
            +
                  when :javascripts
         | 
| 80 | 
            +
                    @assets[type].collect do |asset|
         | 
| 81 | 
            +
                      [ to.split('javascripts/')[1], File.basename(asset, '.js') ].join '/'
         | 
| 175 82 | 
             
                    end
         | 
| 176 | 
            -
                   | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
                    return nil if @rendered[type][options[:id]]
         | 
| 181 | 
            -
                    @rendered[type][options[:id]] = true
         | 
| 182 | 
            -
                    
         | 
| 183 | 
            -
                    @assets["init_#{type}".intern].collect do |f|
         | 
| 184 | 
            -
                      @controller.render_to_string :file => f, :locals => options.merge(:options => options)
         | 
| 185 | 
            -
                    end.join("\n")
         | 
| 186 | 
            -
                  end
         | 
| 187 | 
            -
                  
         | 
| 188 | 
            -
                  private
         | 
| 189 | 
            -
                  
         | 
| 190 | 
            -
                  def cache_name
         | 
| 191 | 
            -
                    'cache/' + (@path.empty? ? 'base' : @path.gsub('/', '_'))
         | 
| 192 | 
            -
                  end
         | 
| 193 | 
            -
                  
         | 
| 194 | 
            -
                  def filename_to_partial(file, remove=nil)
         | 
| 195 | 
            -
                    base = File.basename file
         | 
| 196 | 
            -
                    dir  = File.dirname file
         | 
| 197 | 
            -
                    file = [ dir, (base[0..0] == '_' ? base[1..-1] : base ).split('.')[0..-2].join('.') ].join '/'
         | 
| 198 | 
            -
                    if remove
         | 
| 199 | 
            -
                      if remove.respond_to?(:pop)
         | 
| 200 | 
            -
                        remove.each { |r| file.gsub! r, '' }
         | 
| 201 | 
            -
                      else
         | 
| 202 | 
            -
                        file.gsub! remove, ''
         | 
| 203 | 
            -
                      end
         | 
| 83 | 
            +
                  when :stylesheets
         | 
| 84 | 
            +
                    @assets[type].collect do |asset|
         | 
| 85 | 
            +
                      sass = asset.include? '.sass'
         | 
| 86 | 
            +
                      [ to.split('stylesheets/')[1], File.basename(asset, sass ? '.sass' : '.css') ].join '/'
         | 
| 204 87 | 
             
                    end
         | 
| 205 | 
            -
             | 
| 88 | 
            +
                  else @assets[type]
         | 
| 206 89 | 
             
                  end
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
                
         | 
| 92 | 
            +
                # Renders and returns the init file for a particular <tt>ASSET_TYPE</tt>.
         | 
| 93 | 
            +
                #
         | 
| 94 | 
            +
                # The render will not occur if it has already happened with the same <tt>:id</tt> option.
         | 
| 95 | 
            +
                #
         | 
| 96 | 
            +
                def render_init(type, options=@options)
         | 
| 97 | 
            +
                  @rendered[type] ||= {}
         | 
| 98 | 
            +
                  #return nil if @rendered[type][options[:id]]
         | 
| 99 | 
            +
                  @rendered[type][options[:id]] = true
         | 
| 207 100 |  | 
| 208 | 
            -
                   | 
| 209 | 
            -
                     | 
| 210 | 
            -
                  end
         | 
| 211 | 
            -
             | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
                     | 
| 223 | 
            -
             | 
| 224 | 
            -
                     | 
| 101 | 
            +
                  @assets["init_#{type}".intern].collect do |f|
         | 
| 102 | 
            +
                    @controller.render_to_string :file => f, :locals => options.merge(:options => options)
         | 
| 103 | 
            +
                  end.join("\n")
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                private
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                # Converts a full file name to a path that can be used by <tt>render :partial</tt>.
         | 
| 109 | 
            +
                #
         | 
| 110 | 
            +
                def filename_to_partial(file, remove=nil) #:doc:
         | 
| 111 | 
            +
                  base = File.basename file
         | 
| 112 | 
            +
                  dir  = File.dirname file
         | 
| 113 | 
            +
                  file = [ dir, (base[0..0] == '_' ? base[1..-1] : base ).split('.')[0..-2].join('.') ].join '/'
         | 
| 114 | 
            +
                  if remove
         | 
| 115 | 
            +
                    if remove.respond_to?(:pop)
         | 
| 116 | 
            +
                      remove.each { |r| file.gsub! r, '' }
         | 
| 117 | 
            +
                    else
         | 
| 118 | 
            +
                      file.gsub! remove, ''
         | 
| 225 119 | 
             
                    end
         | 
| 226 120 | 
             
                  end
         | 
| 227 | 
            -
                  
         | 
| 228 | 
            -
             | 
| 229 | 
            -
             | 
| 230 | 
            -
             | 
| 231 | 
            -
             | 
| 232 | 
            -
             | 
| 233 | 
            -
             | 
| 234 | 
            -
             | 
| 235 | 
            -
             | 
| 236 | 
            -
             | 
| 121 | 
            +
                  file
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
                
         | 
| 124 | 
            +
                # Returns true if <tt>from</tt> is newer than <tt>to</tt> or <tt>to</tt> does not exist.
         | 
| 125 | 
            +
                #
         | 
| 126 | 
            +
                def needs_update?(from, to) #:doc:
         | 
| 127 | 
            +
                  File.exists?(to) ? File.mtime(from) > File.mtime(to) : true
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
                
         | 
| 130 | 
            +
                # Returns a full path for the specified <tt>ASSET_TYPE</tt>.
         | 
| 131 | 
            +
                #
         | 
| 132 | 
            +
                def to_path(type, path=@path) #:doc:
         | 
| 133 | 
            +
                  slash = path.empty? ? '' : '/'
         | 
| 134 | 
            +
                  base  = "app/widgets#{slash}#{path}"
         | 
| 135 | 
            +
                  case type
         | 
| 136 | 
            +
                  when :base:          base
         | 
| 137 | 
            +
                  when :init_css:      base + '/stylesheets/init'
         | 
| 138 | 
            +
                  when :init_js:       base + '/javascripts/init'
         | 
| 139 | 
            +
                  when :init_partials: base + '/partials/_init'
         | 
| 140 | 
            +
                  when :options:       base + '/options.rb'
         | 
| 141 | 
            +
                  when :templates:     base + '/templates'
         | 
| 142 | 
            +
                  when :flash:       [ base + '/flash',       "public/flash/widgets"       + slash + path ]
         | 
| 143 | 
            +
                  when :images:      [ base + '/images',      "public/images/widgets"      + slash + path ]
         | 
| 144 | 
            +
                  when :javascripts: [ base + '/javascripts', "public/javascripts/widgets" + slash + path ]
         | 
| 145 | 
            +
                  when :stylesheets: [ base + '/stylesheets', "public/stylesheets/widgets" + slash + path ]
         | 
| 237 146 | 
             
                  end
         | 
| 238 | 
            -
             | 
| 239 | 
            -
             | 
| 240 | 
            -
             | 
| 241 | 
            -
             | 
| 242 | 
            -
             | 
| 243 | 
            -
             | 
| 244 | 
            -
             | 
| 147 | 
            +
                end
         | 
| 148 | 
            +
                
         | 
| 149 | 
            +
                # Updates <tt>@assets[type]</tt> with an array of paths for the specified <tt>ASSET_TYPE</tt>.
         | 
| 150 | 
            +
                #
         | 
| 151 | 
            +
                def update_asset(type) #:doc:
         | 
| 152 | 
            +
                  @assets[type] ||= []
         | 
| 153 | 
            +
                  from = to_path type
         | 
| 154 | 
            +
                  from = from[0] if from.respond_to?(:pop)
         | 
| 155 | 
            +
                  from = File.directory?(from) ? "#{from}/*" : "#{from}.*"
         | 
| 156 | 
            +
                  Dir[from].sort.each do |f|
         | 
| 157 | 
            +
                    next if (type == :javascripts || type == :stylesheets) && File.basename(f)[0..3] == 'init'
         | 
| 158 | 
            +
                    @assets[type] << (type == :templates ? filename_to_partial(f, 'app/widgets/') : f)
         | 
| 245 159 | 
             
                  end
         | 
| 246 160 | 
             
                end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                # Assigns <tt>@options</tt> to the hash in <tt>options.rb</tt> (if it exists).
         | 
| 163 | 
            +
                #
         | 
| 164 | 
            +
                def update_options(path=@path, empty=false) #:doc:
         | 
| 165 | 
            +
                  path = to_path :options, path
         | 
| 166 | 
            +
                  @options = File.exists?(path) ? eval(File.read(path), @bind) : {}
         | 
| 167 | 
            +
                end
         | 
| 247 168 | 
             
              end
         | 
| 248 169 | 
             
            end
         | 
| @@ -0,0 +1,188 @@ | |
| 1 | 
            +
            module RailsWidget
         | 
| 2 | 
            +
              
         | 
| 3 | 
            +
              # See <tt>RailsWidget</tt>.
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              def widget(*path)
         | 
| 6 | 
            +
                @assets  ||= Assets.new  binding, controller, logger
         | 
| 7 | 
            +
                @widgets ||= Widgets.new @assets, binding, controller, logger
         | 
| 8 | 
            +
                options = path.extract_options!
         | 
| 9 | 
            +
                @widgets.build path, options
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
              # Returns a path for a flash asset.
         | 
| 13 | 
            +
              #
         | 
| 14 | 
            +
              # ==== Example
         | 
| 15 | 
            +
              #   <%= flash_path :some, :widget, 'flash.swf' %>
         | 
| 16 | 
            +
              #   # => 'app/widgets/some/widget/flash/flash.swf'
         | 
| 17 | 
            +
              #
         | 
| 18 | 
            +
              def flash_path(*path)
         | 
| 19 | 
            +
                flash = path.pop
         | 
| 20 | 
            +
                "/flash/widgets/#{path.join('/')}/#{flash}"
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
              
         | 
| 23 | 
            +
              # Returns an image tag for a image asset.
         | 
| 24 | 
            +
              #
         | 
| 25 | 
            +
              # ==== Example
         | 
| 26 | 
            +
              #   <%= image :some, :widget, 'image.png', :border => 0 %>
         | 
| 27 | 
            +
              #   # => '<img src="app/widgets/some/widget/images/image.png" border=0 />'
         | 
| 28 | 
            +
              #
         | 
| 29 | 
            +
              def image(*path)
         | 
| 30 | 
            +
                options = path.extract_options!
         | 
| 31 | 
            +
                image = path.pop
         | 
| 32 | 
            +
                image_tag "widgets/#{path.join('/')}/#{image}", options
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
              
         | 
| 35 | 
            +
              # Returns an image path for a image asset.
         | 
| 36 | 
            +
              #
         | 
| 37 | 
            +
              # ==== Example
         | 
| 38 | 
            +
              #   <%= image_path :some, :widget, 'image.png' %>
         | 
| 39 | 
            +
              #   # => 'app/widgets/some/widget/images/image.png'
         | 
| 40 | 
            +
              #
         | 
| 41 | 
            +
              def image_path(*path)
         | 
| 42 | 
            +
                image = path.pop
         | 
| 43 | 
            +
                "/images/widgets/#{path.join('/')}/#{image}"
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
              
         | 
| 46 | 
            +
              # Renders a partial asset.
         | 
| 47 | 
            +
              #
         | 
| 48 | 
            +
              # ==== Example
         | 
| 49 | 
            +
              #   <%= partial :some, :widget, 'partial', :locals => { :x => true } %>
         | 
| 50 | 
            +
              #   # => render :partial => 'app/widgets/some/widget/partials/partial', :locals => { :x => true }
         | 
| 51 | 
            +
              #
         | 
| 52 | 
            +
              def partial(*path)
         | 
| 53 | 
            +
                options = path.extract_options!
         | 
| 54 | 
            +
                partial = path.pop
         | 
| 55 | 
            +
                path << options
         | 
| 56 | 
            +
                widgets, options = widget_instances path
         | 
| 57 | 
            +
                options = {
         | 
| 58 | 
            +
                  :locals  => options.merge(:options => options),
         | 
| 59 | 
            +
                  :partial => "#{path.join('/')}/partials/#{partial}"
         | 
| 60 | 
            +
                }
         | 
| 61 | 
            +
                render options
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
              
         | 
| 64 | 
            +
              # Creates and recycles instances of the Widget class.
         | 
| 65 | 
            +
              #
         | 
| 66 | 
            +
              class Widgets
         | 
| 67 | 
            +
                attr :widgets, true
         | 
| 68 | 
            +
                
         | 
| 69 | 
            +
                # Should be called from a helper. See <tt>widget (RailsWidget)</tt>.
         | 
| 70 | 
            +
                #
         | 
| 71 | 
            +
                # ==== Example
         | 
| 72 | 
            +
                #   w = Widgets.new Assets.new(binding, controller), binding, controller, logger
         | 
| 73 | 
            +
                #
         | 
| 74 | 
            +
                def initialize(assets, bind, controller, logger)
         | 
| 75 | 
            +
                  @assets     = assets
         | 
| 76 | 
            +
                  @bind       = bind
         | 
| 77 | 
            +
                  @controller = controller
         | 
| 78 | 
            +
                  @logger     = logger
         | 
| 79 | 
            +
                  @widgets    = {}
         | 
| 80 | 
            +
                  build
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
                
         | 
| 83 | 
            +
                # See <tt>widget (RailsWidget)</tt>.
         | 
| 84 | 
            +
                #
         | 
| 85 | 
            +
                def build(path=[''], options={})
         | 
| 86 | 
            +
                  widgets, opts = instanciate path
         | 
| 87 | 
            +
                  options = opts.merge options        # Merge the options parameter (highest precedence)
         | 
| 88 | 
            +
                  add_static_assets  widgets, options
         | 
| 89 | 
            +
                  return_init_assets widgets, options # Returns the init partial to <tt>widget (RailsWidget)</tt>
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
                
         | 
| 92 | 
            +
                # Creates Widget instances for the widget path and its <tt>related_paths</tt> if they do not already exist.
         | 
| 93 | 
            +
                #
         | 
| 94 | 
            +
                # Returns an array of widget instances and merged <tt>options.rb</tt> hashes.
         | 
| 95 | 
            +
                #
         | 
| 96 | 
            +
                # ==== Example
         | 
| 97 | 
            +
                #   w.build([ :some, :widget ], { :option1 => true })
         | 
| 98 | 
            +
                #   # => [ #<Widget>, #<Widget>, #<Widget> ], { :option1 => true, :option2 => true }
         | 
| 99 | 
            +
                #
         | 
| 100 | 
            +
                # (See the <tt>related_paths</tt> example for context.)
         | 
| 101 | 
            +
                #
         | 
| 102 | 
            +
                def instanciate(path)
         | 
| 103 | 
            +
                  opts = {}
         | 
| 104 | 
            +
                  widgets = related_paths(path).collect do |r|
         | 
| 105 | 
            +
                    @widgets[r] ||= Widget.new r, @bind, @controller, @logger
         | 
| 106 | 
            +
                    opts.merge! @widgets[r].options
         | 
| 107 | 
            +
                    @widgets[r]
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
                  [ widgets, opts ]
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
                
         | 
| 112 | 
            +
                # Calls <tt>copy_assets (Widget)</tt> for a number of <tt>Widget</tt> instances.
         | 
| 113 | 
            +
                #
         | 
| 114 | 
            +
                # Also adds static (non-init) assets to the layout via the Assets helpers.
         | 
| 115 | 
            +
                #
         | 
| 116 | 
            +
                def add_static_assets(widgets, options)
         | 
| 117 | 
            +
                  widgets.each do |w|
         | 
| 118 | 
            +
                    w.copy_assets
         | 
| 119 | 
            +
                    js  = w.asset_paths :javascripts
         | 
| 120 | 
            +
                    css = w.asset_paths :stylesheets
         | 
| 121 | 
            +
                    @assets.javascripts *(js  + [ :cache => w.cache ]) unless js.empty?
         | 
| 122 | 
            +
                    @assets.stylesheets *(css + [ :cache => w.cache ]) unless css.empty?
         | 
| 123 | 
            +
                    @assets.templates   *(w.assets[:templates].collect do |t|
         | 
| 124 | 
            +
                      { :id => File.basename(t), :partial => t, :locals => options.merge(:options => options) }
         | 
| 125 | 
            +
                    end) unless w.assets[:templates].empty?
         | 
| 126 | 
            +
                  end
         | 
| 127 | 
            +
                end
         | 
| 128 | 
            +
                
         | 
| 129 | 
            +
                # Renders and returns the init partial (<tt>partials/_init.*</tt>) for a number of <tt>Widget</tt> instances.
         | 
| 130 | 
            +
                #
         | 
| 131 | 
            +
                # The <tt>:include_js => true</tt> option appends <tt>javascripts/init.js</tt> in <script> tags.
         | 
| 132 | 
            +
                # Use this option when rendering a widget in an Ajax response.
         | 
| 133 | 
            +
                #
         | 
| 134 | 
            +
                def return_init_assets(widgets, options)
         | 
| 135 | 
            +
                  # Render partials/_init.* (options[:include_js] will render javascripts/init.js in <script> tags)
         | 
| 136 | 
            +
                  widgets.collect do |w|
         | 
| 137 | 
            +
                    # We want widgets rendered from the partial to include first
         | 
| 138 | 
            +
                    partial = w.render_init :partials, options
         | 
| 139 | 
            +
                    css = w.render_init :css, options
         | 
| 140 | 
            +
                    js  = w.render_init :js,  options
         | 
| 141 | 
            +
                    if options[:include_js] && js && !js.empty?
         | 
| 142 | 
            +
                      partial + "\n<script type='text/javascript'>\n#{js}\n</script>"
         | 
| 143 | 
            +
                    else
         | 
| 144 | 
            +
                      @assets.stylesheets do
         | 
| 145 | 
            +
                        css
         | 
| 146 | 
            +
                      end unless css.empty?
         | 
| 147 | 
            +
                      @assets.javascripts do
         | 
| 148 | 
            +
                        js
         | 
| 149 | 
            +
                      end unless js.empty?
         | 
| 150 | 
            +
                      partial
         | 
| 151 | 
            +
                    end
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
                
         | 
| 155 | 
            +
                private
         | 
| 156 | 
            +
                
         | 
| 157 | 
            +
                # Returns an array of related paths based on a single widget path.
         | 
| 158 | 
            +
                #
         | 
| 159 | 
            +
                # ==== Example
         | 
| 160 | 
            +
                #   related_paths([ :some, :widget ])
         | 
| 161 | 
            +
                #   # => [ 'some', 'widget', 'some/widget' ]
         | 
| 162 | 
            +
                #
         | 
| 163 | 
            +
                # Options are merged based on the order of the array that <tt>related_paths</tt> returns:
         | 
| 164 | 
            +
                #   app/widgets/some/options.rb         # { :option1 => true, :option2 => false }
         | 
| 165 | 
            +
                #   app/widgets/widget/options.rb       # { :option1 => false }
         | 
| 166 | 
            +
                #   app/widgets/some/widget/options.rb  # { :option2 => true }
         | 
| 167 | 
            +
                #
         | 
| 168 | 
            +
                # Sequentially merging the options in this example produces <tt>{ :option1 => false, :option2 => true }</tt>.
         | 
| 169 | 
            +
                #
         | 
| 170 | 
            +
                # Assets are also included and rendered (init files) in the order of the <tt>related_paths</tt> array.
         | 
| 171 | 
            +
                #
         | 
| 172 | 
            +
                def related_paths(paths)
         | 
| 173 | 
            +
                  ordered = []
         | 
| 174 | 
            +
                  last = paths.length - 1
         | 
| 175 | 
            +
                  paths.each_index do |x|
         | 
| 176 | 
            +
                    if x != 0 && File.exists?("app/widgets/#{paths[x]}")
         | 
| 177 | 
            +
                      ordered << related_paths(paths[x..last])
         | 
| 178 | 
            +
                    end
         | 
| 179 | 
            +
                    path = paths[0..x].join '/'
         | 
| 180 | 
            +
                    if File.exists?("app/widgets/#{path}")
         | 
| 181 | 
            +
                      ordered << path
         | 
| 182 | 
            +
                    end
         | 
| 183 | 
            +
                  end
         | 
| 184 | 
            +
                  ordered.flatten
         | 
| 185 | 
            +
                end
         | 
| 186 | 
            +
              end
         | 
| 187 | 
            +
              
         | 
| 188 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: winton-rails_widget
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: "1.1"
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
            - Winton Welsh
         | 
| @@ -9,11 +9,11 @@ autorequire: | |
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 11 |  | 
| 12 | 
            -
            date: 2008-08 | 
| 12 | 
            +
            date: 2008-11-08 00:00:00 -08:00
         | 
| 13 13 | 
             
            default_executable: 
         | 
| 14 14 | 
             
            dependencies: []
         | 
| 15 15 |  | 
| 16 | 
            -
            description:  | 
| 16 | 
            +
            description: Allows you to group your client-side assets into distributable widgets
         | 
| 17 17 | 
             
            email: mail@wintoni.us
         | 
| 18 18 | 
             
            executables: []
         | 
| 19 19 |  | 
| @@ -25,12 +25,12 @@ files: | |
| 25 25 | 
             
            - init.rb
         | 
| 26 26 | 
             
            - lib/rails_widget.rb
         | 
| 27 27 | 
             
            - lib/rails_widget
         | 
| 28 | 
            +
            - lib/rails_widget/widgets.rb
         | 
| 28 29 | 
             
            - lib/rails_widget/assets.rb
         | 
| 29 30 | 
             
            - lib/rails_widget/widget.rb
         | 
| 30 31 | 
             
            - MIT-LICENSE
         | 
| 31 32 | 
             
            - README.markdown
         | 
| 32 | 
            -
             | 
| 33 | 
            -
            has_rdoc: false
         | 
| 33 | 
            +
            has_rdoc: true
         | 
| 34 34 | 
             
            homepage: http://github.com/winton/rails_widget
         | 
| 35 35 | 
             
            post_install_message: 
         | 
| 36 36 | 
             
            rdoc_options: []
         | 
| @@ -55,6 +55,6 @@ rubyforge_project: | |
| 55 55 | 
             
            rubygems_version: 1.2.0
         | 
| 56 56 | 
             
            signing_key: 
         | 
| 57 57 | 
             
            specification_version: 2
         | 
| 58 | 
            -
            summary:  | 
| 58 | 
            +
            summary: Allows you to group your client-side assets into distributable widgets
         | 
| 59 59 | 
             
            test_files: []
         | 
| 60 60 |  | 
    
        data/tasks/rails_widget.rake
    DELETED
    
    | @@ -1,31 +0,0 @@ | |
| 1 | 
            -
            desc 'Updates app/widgets assets'
         | 
| 2 | 
            -
            task :widgets => [ 'widgets:javascripts', 'widgets:stylesheets' ]
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            namespace :widgets do    
         | 
| 5 | 
            -
              desc 'Updates app/widgets/javascripts'
         | 
| 6 | 
            -
              task :javascripts do
         | 
| 7 | 
            -
                rails_widget_resource 'widgets/javascripts', 'app/widgets/javascripts'
         | 
| 8 | 
            -
              end
         | 
| 9 | 
            -
              
         | 
| 10 | 
            -
              desc 'Updates app/widgets/stylesheets'
         | 
| 11 | 
            -
              task :stylesheets do
         | 
| 12 | 
            -
                rails_widget_resource 'widgets/stylesheets', 'app/widgets/stylesheets'
         | 
| 13 | 
            -
              end
         | 
| 14 | 
            -
              
         | 
| 15 | 
            -
              def rails_widget_resource(type, to, reverse=false)
         | 
| 16 | 
            -
                from = "#{File.dirname(__FILE__)}/../resources/#{type}"
         | 
| 17 | 
            -
                from, to = to, from if reverse
         | 
| 18 | 
            -
                puts "=> Removing old #{type}..."
         | 
| 19 | 
            -
                FileUtils.remove_dir to, true
         | 
| 20 | 
            -
                FileUtils.mkdir_p to
         | 
| 21 | 
            -
                puts "=> Copying #{type}..."
         | 
| 22 | 
            -
                Dir["#{from}/*"].each do |f|
         | 
| 23 | 
            -
                  if File.directory? f
         | 
| 24 | 
            -
                    FileUtils.mkdir_p "#{to}/#{File.basename(f)}"
         | 
| 25 | 
            -
                    FileUtils.cp_r f, to
         | 
| 26 | 
            -
                  else
         | 
| 27 | 
            -
                    FileUtils.cp f, to
         | 
| 28 | 
            -
                  end
         | 
| 29 | 
            -
                end
         | 
| 30 | 
            -
              end
         | 
| 31 | 
            -
            end
         |