<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lipsiadmin_generators/attachment/templates/controller.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,10 @@
+2009-05-26
+  * Fixed validates_attachment_content_type_for, now accepts correctly regex
+  * Added a attachment_tag for autogenerate html for upload one file/image
+  * Added a attachemnts_tag autogenerate html for upload multiple file/image and order them
+  * Added a open_standard_grid for simplify use of ext window with ours grids.
+  * Improved attachment generator
+
 2009-05-21
   * Removed some grids defaults
   * Added attacher_name in before_save</diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -75,7 +75,7 @@ end
 
 desc &quot;Publish the API documentation&quot;
 task :pdoc =&gt; [:rdoc] do 
-  Rake::SshDirPublisher.new(&quot;root@lipsiasoft.net&quot;, &quot;/mnt/www/apps/lipsiadmin/doc&quot;, &quot;doc&quot;).upload
+  Rake::SshDirPublisher.new(&quot;root@lipsiasoft.net&quot;, &quot;/mnt/www/apps/lipsiasoft/doc&quot;, &quot;doc&quot;).upload
 end
 
 desc &quot;Publish the release files to RubyForge.&quot;</diff>
      <filename>Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -347,8 +347,8 @@ module Lipsiadmin
           valid_types = []
           args.each do |variable|
             case variable
-              when String then valid_types &lt;&lt; variable
               when Hash   then options.merge!(variable)
+              else valid_types &lt;&lt; variable
             end
           end
           attachment_definitions[name][:validations][:content_type] = lambda do |attachment, instance|</diff>
      <filename>lib/data_base/attachment.rb</filename>
    </modified>
    <modified>
      <diff>@@ -43,7 +43,6 @@ module Lipsiadmin
       def options
         @options ||= {
           :whiny_thumbnails  =&gt; false,
-          :image_magick_path =&gt; nil,
           :command_path      =&gt; nil,
           :log               =&gt; true,
           :swallow_stderr    =&gt; true
@@ -83,9 +82,6 @@ module Lipsiadmin
       end
       
       def path_for_command(command)#:nodoc:
-        if options[:image_magick_path]
-          warn(&quot;[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead&quot;)
-        end
         path = [options[:command_path] || options[:image_magick_path], command].compact
         File.join(*path)
       end</diff>
      <filename>lib/data_base/attachment/attach.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,7 +2,7 @@ module Lipsiadmin
   module VERSION #:nodoc:
     MAJOR = 4
     MINOR = 1
-    TINY  = 3
+    TINY  = 4
 
     STRING = [MAJOR, MINOR, TINY].join('.')
   end</diff>
      <filename>lib/version.rb</filename>
    </modified>
    <modified>
      <diff>@@ -157,8 +157,164 @@ module Lipsiadmin
           config &lt;&lt; { :text =&gt; I18n.t(&quot;backend.menus.help&quot;, :default =&gt; &quot;Help&quot;), :handler =&gt; &quot;function() { Backend.app.openHelp() }&quot;.to_l }
           return config.to_json
         end
+
+        # Returns html for upload one image or generic file.
+        # 
+        # Options can be one of the following:
+        # 
+        # &lt;tt&gt;:image&lt;/tt&gt;::     Indicate if the attachments are ONLY images.
+        # 
+        # Examples:
+        # 
+        #   class Category &lt; ActiveRecord::Base
+        #     has_one_attachments    :file,   :dependent =&gt; :destroy
+        #   ...
+        # 
+        # Then in our view we can simply add this:
+        # 
+        #   attachments_tag(:category, :file)
+        # 
+        # Remember that al labels can be translated. See Locales for Backend.
+        # 
+        def attachment_tag(object_name, method, options={})
+          variable = instance_variable_get(&quot;@#{object_name}&quot;)
+          html     = []
+          html    &lt;&lt; '&lt;!-- Generated from Lipsiadmin --&gt;'
+          html    &lt;&lt; '&lt;ul id=&quot;' + &quot;#{method}-order&quot; + '&quot; class=&quot;label&quot;&gt;'
+
+          if attachment = variable.send(method)
+            # Create first the remove link
+            remove_link = link_to_remote(tl(:remove), :url =&gt; &quot;/backend/attachments/#{attachment.id}&quot;, 
+                                                      :method =&gt; :delete, 
+                                                      :success =&gt; &quot;$('#{method}_#{attachment.id}').remove();&quot;)
+
+            if options[:image]
+              fstyle  = &quot;float:left;margin:5px;margin-left:0px;&quot;
+              fclass  = &quot;box-image&quot;
+              ftag    = '&lt;div&gt;' + image_tag(attachment.url(:thumb)) + '&lt;/div&gt;'
+              ftag   += '&lt;div style=&quot;text-align:center;padding:5px;cursor:pointer&quot;&gt;'
+              ftag   += '  ' + remove_link
+              ftag   += '&lt;/div&gt;'
+            else
+              fstyle  = &quot;padding:5px;border-bottom:1px solid #DDE7F5;&quot;
+              fclass  = &quot;box-file&quot;
+              ftag    = '&lt;div style=&quot;float:left;cursor:pointer&quot;&gt;'
+              ftag   += ' ' + link_to(attachment.attached_file_name, attachment.url) + ' ' + number_to_human_size(attachment.attached_file_size)
+              ftag   += '&lt;/div&gt;'
+              ftag   += '&lt;div style=&quot;float:right;cursor:pointer&quot;&gt;'
+              ftag   += '  ' + remove_link
+              ftag   += '&lt;/div&gt;'
+              ftag   += '&lt;br style=&quot;clear:both&quot; /&gt;'
+            end
+
+            html &lt;&lt; '&lt;li id=&quot;' + &quot;#{method}_#{attachment.id}&quot; + '&quot; class=&quot;' + fclass + '&quot; style=&quot;' + fstyle + '&quot;&gt;'
+            html &lt;&lt; ' ' + ftag
+            html &lt;&lt; '&lt;/li&gt;'
+          end # End of Loop
+
+          html &lt;&lt; '&lt;/ul&gt;'
+          html &lt;&lt; '&lt;br style=&quot;clear:both&quot; /&gt;'
+
+          flbl = options[:image] ? :upload_image : :upload_file
+          html &lt;&lt; '&lt;div class=&quot;label-title&quot;&gt;' + tl(flbl) + '&lt;/div&gt;'
+          html &lt;&lt; '&lt;table&gt;'
+          rowa  = '  &lt;tr class=&quot;attachment&quot;&gt;'
+          rowa &lt;&lt; '    &lt;td&gt;' + human_name_for(:attachment, :attached_file_name) + '&lt;/td&gt;'
+          rowa &lt;&lt; '    &lt;td&gt;' + file_field_tag(&quot;category[#{method}_attributes][file]&quot;, :style =&gt; &quot;width:250px&quot;) + '&lt;/td&gt;'
+          rowa &lt;&lt; '  &lt;/tr&gt;'
+          html &lt;&lt; rowa
+          html &lt;&lt; '&lt;/table&gt;'
+          html.join(&quot;\n&quot;)
+        end
         
-        # Open a new windows that can contain a grid that you can reuse
+        # Returns html for upload multiple images or generic files.
+        # 
+        # Options can be one of the following:
+        # 
+        # &lt;tt&gt;:image&lt;/tt&gt;::     Indicate if the attachments are ONLY images.
+        # &lt;tt&gt;:order&lt;/tt&gt;::     Indicate if user can order files.
+        # 
+        # Examples:
+        # 
+        #   class Category &lt; ActiveRecord::Base
+        #     has_many_attachments    :images,   :dependent =&gt; :destroy
+        #     validates_attachment_content_type_for :images, /^image/
+        #   ...
+        # 
+        # Then in our view we can simply add this:
+        # 
+        #   attachments_tag(:category, :images, :image =&gt; true, :order =&gt; true)
+        # 
+        # Remember that al labels can be translated. See Locales for Backend.
+        # 
+        def attachments_tag(object_name, method, options={})
+          variable = instance_variable_get(&quot;@#{object_name}&quot;)
+          html     = []
+          html    &lt;&lt; '&lt;!-- Generated from Lipsiadmin --&gt;'
+          html    &lt;&lt; '&lt;ul id=&quot;' + &quot;#{method}-order&quot; + '&quot; class=&quot;label&quot;&gt;'
+
+          for attachment in variable.send(method).all(:order =&gt; :position)
+            # Create first the remove link
+            remove_link = link_to_remote(tl(:remove), :url =&gt; &quot;/backend/attachments/#{attachment.id}&quot;, 
+                                                      :method =&gt; :delete, 
+                                                      :success =&gt; &quot;$('#{method}_#{attachment.id}').remove();&quot;)
+
+            if options[:image]
+              fstyle  = &quot;float:left;margin:5px;margin-left:0px;&quot;
+              fstyle += &quot;cursor:move;&quot; if options[:order]
+              fclass  = &quot;box-image&quot;
+              ftag    = '&lt;div&gt;' + image_tag(attachment.url(:thumb)) + '&lt;/div&gt;'
+              ftag   += '&lt;div style=&quot;text-align:center;padding:5px;cursor:pointer&quot;&gt;'
+              ftag   += '  ' + remove_link
+              ftag   += '&lt;/div&gt;'
+            else
+              fstyle  = &quot;padding:5px;border-bottom:1px solid #DDE7F5;&quot;
+              fstyle += &quot;cursor:move;&quot; if options[:order]
+              fclass  = &quot;box-file&quot;
+              ftag    = '&lt;div style=&quot;float:left;cursor:pointer&quot;&gt;'
+              ftag   += ' ' + link_to(attachment.attached_file_name, attachment.url) + ' ' + number_to_human_size(attachment.attached_file_size)
+              ftag   += '&lt;/div&gt;'
+              ftag   += '&lt;div style=&quot;float:right;cursor:pointer&quot;&gt;'
+              ftag   += '  ' + remove_link
+              ftag   += '&lt;/div&gt;'
+              ftag   += '&lt;br style=&quot;clear:both&quot; /&gt;'
+            end
+
+            html &lt;&lt; '&lt;li id=&quot;' + &quot;#{method}_#{attachment.id}&quot; + '&quot; class=&quot;' + fclass + '&quot; style=&quot;' + fstyle + '&quot;&gt;'
+            html &lt;&lt; ' ' + ftag
+            html &lt;&lt; '&lt;/li&gt;'
+          end # End of Loop
+
+          html &lt;&lt; '&lt;/ul&gt;'
+          html &lt;&lt; '&lt;br style=&quot;clear:both&quot; /&gt;'
+
+          if options[:order]
+            constraint = options[:image] ? &quot;horizontal&quot; : &quot;vertical&quot;
+            html &lt;&lt; '&lt;div id=&quot;' + &quot;#{method}-message&quot; + '&quot; style=&quot;padding:5px&quot;&gt;&amp;nbsp;&lt;/div&gt;'
+            html &lt;&lt; sortable_element(&quot;#{method}-order&quot;, :url =&gt; &quot;/backend/attachments/order&quot;, :update =&gt; &quot;#{method}-message&quot;, :constraint =&gt; constraint,
+                                                        :complete =&gt; visual_effect(:highlight, &quot;#{method}-message&quot;, :duration =&gt; 0.5))
+          end
+
+          flbl = options[:image] ? :upload_images : :upload_files
+          html &lt;&lt; '&lt;div class=&quot;label-title&quot;&gt;'+ tl(flbl) +'&lt;/div&gt;'
+          html &lt;&lt; '&lt;table&gt;'
+          rowa  = '  &lt;tr class=&quot;attachment&quot;&gt;'
+          rowa &lt;&lt; '    &lt;td&gt;' + human_name_for(:attachment, :attached_file_name) + '&lt;/td&gt;'
+          rowa &lt;&lt; '    &lt;td&gt;' + file_field_tag(&quot;category[#{method}_attributes][][file]&quot;, :style =&gt; &quot;width:250px&quot;) + '&lt;/td&gt;'
+          rowa &lt;&lt; '    &lt;td&gt;' + link_to_function(tl(:remove), &quot;this.up('.attachment').remove()&quot;) + '&lt;/td&gt;'
+          rowa &lt;&lt; '  &lt;/tr&gt;'
+          html &lt;&lt; rowa
+          html &lt;&lt; ' &lt;tr id=&quot;' + &quot;add-#{method}&quot; + '&quot;&gt;'
+          html &lt;&lt; '  &lt;td colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/td&gt;'
+          html &lt;&lt; '  &lt;td style=&quot;padding-top:15px&quot;&gt;'
+          html &lt;&lt; '     ' + link_to_function(tl(:add)) { |page| page.insert_html(:before, &quot;add-#{method}&quot;, rowa) }
+          html &lt;&lt; '  &lt;/td&gt;'
+          html &lt;&lt; ' &lt;/tr&gt;'
+          html &lt;&lt; '&lt;/table&gt;'
+          html.join(&quot;\n&quot;)
+        end
+
+        # Build a new windows that can contain an existent grid
         # 
         # The first argument name is used as the link text.
         # 
@@ -187,12 +343,11 @@ module Lipsiadmin
         #   #     }
         #   #   }).show();
         #   #   return false;&quot; href=&quot;#&quot;&gt;Select a Category&lt;/a&gt;
-        # 
-        #   open_grid &quot;Select a Category&quot;, &quot;/backend/categories.js&quot;, &quot;gridPanel&quot;,
+        #   build_grid &quot;Select a Category&quot;, &quot;/backend/categories.js&quot;, &quot;gridPanel&quot;,
         #     :update =&gt; &quot;$('post_category_ids').value = selections.collect(function(s) { return s.id }).join(',');&quot; +
         #     &quot;$('category_names').innerHTML = selections.collect(function(s) { return s.data['categories.name'] }).join(', ');&quot;
         # 
-        def open_grid(text, url, grid, options={})
+        def build_grid(text, url, grid, options={})
           options[:before] = options[:before] + &quot;;&quot; if options[:before]
           javascript = &lt;&lt;-JAVASCRIPT
             #{options[:before]}
@@ -206,7 +361,56 @@ module Lipsiadmin
               }
             }).show()
           JAVASCRIPT
-          link_to_function(text, javascript)
+          link_to_function(text, javascript.gsub(/\n|\s+/, &quot; &quot;))
+        end
+        alias_method :open_grid, :build_grid
+
+        # Open a Standard window that can contain a standard existent grid
+        # 
+        # Options can be one of the following:
+        # 
+        # &lt;tt&gt;:grid&lt;/tt&gt;::       The name of the grid var. Default &quot;gridPanel&quot;
+        # &lt;tt&gt;:url&lt;/tt&gt;::        The url where the grid is stored. Default is autogenerated.
+        # &lt;tt&gt;:name&lt;/tt&gt;::       The name of the link that open the window grid. Default a image.
+        # 
+        #   # Generates: &lt;a onclick=&quot;      
+        #   #   new Backend.window({ 
+        #   #     url: '/backend/categories.js', 
+        #   #     grid: 'gridPanel',  
+        #   #     listeners: {
+        #   #       selected: function(win, selections){
+        #   #         $('post_category_ids').value = selections.collect(function(s) { return s.id }).join(',');
+        #   #         $('category_names').innerHTML = selections.collect(function(s) { return s.data['categories.name'] }).join(', ');
+        #   #       }
+        #   #     }
+        #   #   }).show();
+        #   #   return false;&quot; href=&quot;#&quot;&gt;Select a Category&lt;/a&gt;
+        #   # Generates: new Backend.window({ 
+        #   #   url: '/backend/suppliers.js', 
+        #   #   grid: 'gridPanel', 
+        #   #   listeners: {  
+        #   #     selected: function(win, selections){  
+        #   #       $('warehouse_supplier_id').value = selections.first().id; 
+        #   #       $('warehouse_supplier_name').innerHTML = selections.first().data['suppliers.name']  
+        #   #     }  
+        #   #   }  
+        #   # }).show(); return false;&quot;&gt;
+        #   # &lt;img alt=&quot;New&quot; src=&quot;/images/backend/new.gif?1242655402&quot; style=&quot;vertical-align:bottom&quot; /&gt;&lt;/a&gt;
+        #   # &lt;input id=&quot;warehouse_supplier_id&quot; name=&quot;warehouse[supplier_id]&quot; type=&quot;hidden&quot; value=&quot;16&quot; /&gt;
+        #   open_standard_grid :warehouse, :supplier, :id, :name
+        #
+        def open_standard_grid(object_name, ext_object, value, display, options={})
+          current_value       = instance_variable_get(&quot;@#{object_name}&quot;).send(ext_object).send(display) rescue &quot;Nessuno&quot;
+          value_field         = value.to_s.downcase == &quot;id&quot; ? &quot;id&quot; : &quot;data['#{ext_object.to_s.pluralize}.#{value}']&quot;
+          options[:grid]    ||= &quot;gridPanel&quot;
+          options[:url]     ||= &quot;/backend/#{ext_object.to_s.pluralize}.js&quot;
+          options[:name]    ||= image_tag(&quot;backend/new.gif&quot;, :style =&gt; &quot;vertical-align:bottom&quot;)
+          update_function     = &quot;$('#{object_name}_#{ext_object}_#{value}').value = selections.first().#{value_field}; &quot; + 
+                                &quot;$('#{object_name}_#{ext_object}_#{display}').innerHTML = selections.first().data['#{ext_object.to_s.pluralize}.#{display}']&quot;
+
+          content_tag(:span, current_value, :id =&gt; &quot;#{object_name}_#{ext_object}_#{display}&quot; ) + ' ' +
+          build_grid(options[:name], options[:url], options[:grid], :update =&gt; update_function) +
+          hidden_field(object_name, &quot;#{ext_object}_#{value}&quot;)
         end
 
         # Open a new windows that can contain a form that you can reuse
@@ -250,7 +454,7 @@ module Lipsiadmin
               }
             }).show()
           JAVASCRIPT
-          link_to_function(text, javascript)
+          link_to_function(text, javascript.gsub(/\n/, &quot; &quot;))
         end
         
         # This method call a remote_function and in the same time do a </diff>
      <filename>lib/view/helpers/backend_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,7 +6,11 @@ class AttachmentGenerator &lt; Rails::Generator::Base
       unless options[:skip_migration]
         m.migration_template(&quot;migration.rb&quot;, &quot;db/migrate&quot;, :migration_file_name =&gt; &quot;create_attachments&quot;)
       end
+      m.append(&quot;config/routes.rb&quot;, &quot;    backend.resources :attachments, :collection =&gt; { :order =&gt; :post }&quot;, &quot;map.namespace(:backend) do |backend|&quot;)
+      m.directory('app/controllers/backend')
+      m.directory('app/models')
       m.template('model.rb', 'app/models/attachment.rb')
+      m.template('controller.rb', 'app/controllers/backend/attachments_controller.rb')
       m.readme &quot;../REMEMBER&quot;      
     end
   end </diff>
      <filename>lipsiadmin_generators/attachment/attachment_generator.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,10 +1,12 @@
 class CreateAttachments &lt; ActiveRecord::Migration
   def self.up
     create_table :attachments, :force =&gt; true do |t|
-      t.string     :attached_file_name, :attached_content_type
+      t.string     :attached_file_name, 
+      t.string     :attached_content_type
       t.integer    :attached_file_size
-      t.references :attacher, :polymorphic =&gt; true
+      t.references :attacher,             :polymorphic =&gt; true
       t.string     :attacher_name
+      t.integer    :position,             :default =&gt; 1
       t.timestamps
     end
   end</diff>
      <filename>lipsiadmin_generators/attachment/templates/migration.rb</filename>
    </modified>
    <modified>
      <diff>@@ -18,6 +18,16 @@ en:
       list: &quot;List&quot;
       new: &quot;New&quot;
       help: &quot;Help&quot;
+    labels:
+      none: &quot;Nothing&quot;
+      add: &quot;Add&quot;
+      remove: &quot;Remove&quot;
+      upload_file: &quot;Upload File&quot;
+      upload_files: &quot;Upload Files&quot;
+      upload_image: &quot;Upload Image&quot;
+      upload_images: &quot;Upload Images&quot;
+    texts: 
+      order_updated: Order updated!
     javascripts:
       buttons:
         add: &quot;Add&quot;</diff>
      <filename>lipsiadmin_generators/backend/templates/config/locales/backend/en.yml</filename>
    </modified>
    <modified>
      <diff>@@ -17,6 +17,16 @@ it:
       account: &quot;Account&quot;
       list: &quot;Elenco&quot;
       new: &quot;Nuovo&quot;
+    labels:
+      none: &quot;Nessuno&quot;
+      add: &quot;Aggiungi&quot;
+      remove: &quot;Rimuovi&quot;
+      upload_file: &quot;Carica File&quot;
+      upload_files: &quot;Carica Files&quot;
+      upload_image: &quot;Carica Immagine&quot;
+      upload_images: &quot;Carica Immagini&quot;
+    texts: 
+      order_updated: L'ordine &#232; stato aggiornato!
     javascripts:
       buttons:
         add: &quot;Aggiungi&quot;</diff>
      <filename>lipsiadmin_generators/backend/templates/config/locales/backend/it.yml</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,5 @@
 require 'digest/sha1'
+require 'openssl'
 class Account &lt; ActiveRecord::Base
   # Virtual attribute for the unencrypted password
   attr_accessor :password</diff>
      <filename>lipsiadmin_generators/backend/templates/models/account.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>74239e7aaaa7c5d9f6a69c7e181760687c1aee40</id>
    </parent>
  </parents>
  <author>
    <name>Davide D'Agostino</name>
    <email>DAddYE@DAddYE.local</email>
  </author>
  <url>http://github.com/Lipsiasoft/lipsiadmin/commit/685814e735d54b062b605d3d753b619d2c3119ea</url>
  <id>685814e735d54b062b605d3d753b619d2c3119ea</id>
  <committed-date>2009-05-26T13:46:06-07:00</committed-date>
  <authored-date>2009-05-26T13:46:06-07:00</authored-date>
  <message>  * Fixed validates_attachment_content_type_for, now accepts correctly regex
  * Added a attachment_tag for autogenerate html for upload one file/image
  * Added a attachemnts_tag autogenerate html for upload multiple file/image and order them
  * Added a open_standard_grid for simplify use of ext window with ours grids.</message>
  <tree>933e6477871908a32eeacfaa876046feeb78e642</tree>
  <committer>
    <name>Davide D'Agostino</name>
    <email>DAddYE@DAddYE.local</email>
  </committer>
</commit>
