<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,10 @@
+2009-05-11
+  * Bumped version to 4.0.0
+  * Added editable grids
+  * Refactored backend.js so javascript in tabs are evalued after render so you can interact with tabs
+  * Refactored Backend.window so now you can do much more with your grids/forms. See rdoc for examples.
+  * Small refactor to attachment processor, now original attachments are saved without &quot;_original_&quot; in the filename.
+
 2009-05-07
   * Fixed a problem with WithoutTable
   * Removed unusued routes</diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -28,7 +28,7 @@ Haml 2+
   
 Then in your config/environment.rb
   
-  config.gem &quot;lipsiadmin&quot;, :version =&gt; &quot;&lt; 4.0&quot;
+  config.gem &quot;lipsiadmin&quot;, :version =&gt; &quot;&lt; 5.0&quot;
   
 Why we need to specify version?
 
@@ -52,6 +52,7 @@ So you can do:
   $ script/generate backend # Generate the base admin
   $ script/generate backend_page yourmodel # Generate a &quot;scaffold&quot; for your model
   $ script/generate state_session # Create a &quot;scaffold&quot; for store extjs grid settings in db
+  $ script/generate loops # Generate background workers
   $ script/generate frontend # Generate the base frontend
   $ script/generate attachment # Generate the an attachments
   $ script/generate pdf PdfName # Generate a new pdf document</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -78,6 +78,9 @@ module Lipsiadmin
             end.join(&quot;,&quot;)
           end
           
+          # Adding a name for our column
+          options[:name] ||= &quot;#{@model.table_name.singularize}[#{options[:method]}]&quot;
+          
           # Reformat query
           if options[:method].is_a?(Symbol)
             options[:dataIndex] ||= &quot;#{@model.table_name}.#{options[:method]}&quot;</diff>
      <filename>lib/controller/ext.rb</filename>
    </modified>
    <modified>
      <diff>@@ -115,7 +115,7 @@ module Lipsiadmin
           :path          =&gt; &quot;:rails_root/public/uploads/:id_:style_:basename.:extension&quot;,
           :styles        =&gt; {},
           :default_url   =&gt; &quot;/images/backend/no-image.png&quot;,
-          :default_style =&gt; :normal,
+          :default_style =&gt; :original,
           :validations   =&gt; {},
           :storage       =&gt; :filesystem
         }
@@ -486,9 +486,9 @@ module Lipsiadmin
         interpolations = self.class.interpolations.sort{|a,b| a.first.to_s &lt;=&gt; b.first.to_s }
         interpolations.reverse.inject( pattern.dup ) do |result, interpolation|
           tag, blk = interpolation
-          result.gsub(/:#{tag}/) do |match|
-            blk.call( self, style )
-          end
+          match    = blk.call(self, style)
+          # If we use tag original we dont want to add :original to filename or url
+          tag == :style &amp;&amp; match == :original ? result.gsub(/:style_/, &quot;&quot;) : result.gsub(/:#{tag}/, match.to_s)
         end
       end
 </diff>
      <filename>lib/data_base/attachment/attach.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,8 @@
 module Lipsiadmin
   module VERSION #:nodoc:
-    MAJOR = 3
-    MINOR = 4
-    TINY  = 2
+    MAJOR = 4
+    MINOR = 0
+    TINY  = 0
 
     STRING = [MAJOR, MINOR, TINY].join('.')
   end</diff>
      <filename>lib/version.rb</filename>
    </modified>
    <modified>
      <diff>@@ -47,22 +47,99 @@ module Lipsiadmin
           return config.to_json
         end
         
+        # Open a new windows that can contain a grid that you can reuse
+        # 
+        # The first argument name is used as the link text.
+        # 
+        # The second argument is the url where js of grid are stored.
+        # 
+        # The third argument is the name of the gird var usually gridPanel or editorGridPanel.
+        # 
+        # The four argument are callbacks that may be specified:
+        # 
+        # &lt;tt&gt;:before&lt;/tt&gt;::     Called before request is initiated.
+        # &lt;tt&gt;:update&lt;/tt&gt;::     Called after user press +select+ button.
+        #                        This call are performed in an handler where
+        #                        you have access to two variables:
+        #                        &lt;tt&gt;:win&lt;/tt&gt;::  Backend.window
+        #                        &lt;tt&gt;:selections&lt;/tt&gt;::  Records selected in the grid
+        # 
+        #   # 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;
+        # 
+        #   open_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={})
+          options[:before] = options[:before] + &quot;;&quot; if options[:before]
+          javascript = &lt;&lt;-JAVASCRIPT
+            #{options[:before]}
+            new Backend.window({ 
+              url: '#{url}', 
+              grid: '#{grid}',  
+              listeners: {
+                selected: function(win, selections){
+                  #{options[:update]}
+                }
+              }
+            }).show()
+          JAVASCRIPT
+          link_to_function(text, javascript)
+        end
+
         # Open a new windows that can contain a form that you can reuse
         # 
-        #   Example:
-        #     
-        #     # in app/views/dossiers/_form.html.haml
-        #         %tr
-        #           %td{:style=&gt;&quot;width:100px&quot;} 
-        #             %b Customer:
-        #           %td
-        #             %span{:id =&gt; :account_name}=@dossier.account ? @dossier.account.full_name : &quot;None&quot; 
-        #             =hidden_field :dossier, :account_id
-        #             =open_window &quot;/backend/accounts.js&quot;, :id, :name, :dossier_account_id, :account_name
-        # 
-        def open_window(url, value, display, render_value_to, render_display_to)
-          link_to_function(image_tag(&quot;backend/new.gif&quot;, :style=&gt;&quot;vertical-align:bottom&quot;), 
-            &quot;Backend.window.open({url:'#{url}', display:'#{display}', value:'#{value}', displayField:'#{render_display_to}', valueField:'#{render_value_to}'})&quot;)
+        # The first argument name is used as the link text.
+        # 
+        # The second argument is the url where html of form are stored.
+        # 
+        # The third argument are callbacks that may be specified:
+        # 
+        # &lt;tt&gt;:before&lt;/tt&gt;::     Called before request is initiated.
+        # &lt;tt&gt;:update&lt;/tt&gt;::     Called after user press +save+ button.
+        #                        This call are performed in an handler where
+        #                        you have access to one variables:
+        #                        &lt;tt&gt;:win&lt;/tt&gt;::  Backend.window
+        # 
+        #   # Generates: &lt;a onclick=&quot;  
+        #   #     new Backend.window({ 
+        #   #       url: '/backend/posts/'+$('comment_post_id').value+'/edit', 
+        #   #       form: true,
+        #   #       listeners: {
+        #   #         saved: function(win){
+        #   #           someFn();
+        #   #         }
+        #   #       }
+        #   #     }).show();
+        #   # return false;&quot; href=&quot;#&quot;&gt;Edit Post&lt;/a&gt;
+        #   open_form &quot;Edit Post&quot;, &quot;/backend/posts/'+$('comment_post_id').value+'/edit&quot;, :update =&gt; &quot;someFn();&quot;
+        #   
+        def open_form(text, url, options={})
+          options[:before] = options[:before] + &quot;;&quot; if options[:before]
+          javascript = &lt;&lt;-JAVASCRIPT
+            #{options[:before]}
+            new Backend.window({ 
+              url: '#{url}', 
+              form: true,
+              listeners: {
+                saved: function(win){
+                  #{options[:update]}
+                }
+              }
+            }).show()
+          JAVASCRIPT
+          link_to_function(text, javascript)
         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>@@ -56,9 +56,54 @@ module Lipsiadmin
       #   # Generates: Ext.util.Format.boolRenderer
       #   :renderer =&gt; :boolean
       # 
+      # You can pass :edit_with_###
+      # 
+      #   # Generates: { checkbox: true }
+      #   :editor =&gt; { :xtype =&gt; :checkbox, :someConfig =&gt; true }
+      #   # Generates: new Ext.form.ComboBox({ someConfig =&gt; true });
+      #   :editor =&gt; { :xtype =&gt; :combo, :someConfig =&gt; true }
+      #   # Generates: new Ext.form.DateField({ someConfig =&gt; true });
+      #   :editor =&gt; { :xtype =&gt; :datefield, :someConfig =&gt; true }
+      #   # Generates: new Ext.form.NumberField({ someConfig =&gt; true });
+      #   :editor =&gt; { :xtype =&gt; :numberfield, :someConfig =&gt; true }
+      #   # Generates: new Ext.form.Radio({ someConfig =&gt; true });
+      #   :editor =&gt; { :xtype =&gt; :radio, :someConfig =&gt; true }
+      #   # Generates: new Ext.form.TextArea({ someConfig =&gt; true });
+      #   :editor =&gt; { :xtype =&gt; :textarea, :someConfig =&gt; true }
+      #   # Generates: new Ext.form.TextField({ someConfig =&gt; true });
+      #   :editor =&gt; { :xtype =&gt; :textfield, :someConfig =&gt; true }
+      #   # Generates: new Ext.form.TimeField({ someConfig =&gt; true });
+      #   :editor =&gt; { :xtype =&gt; :timefield, :someConfig =&gt; true }
+      # 
+      #   Form components so are:
+      #   ---------------------------------------
+      #   :checkbox      =&gt;   Ext.form.Checkbox
+      #   :combo         =&gt;   Ext.form.ComboBox
+      #   :datefield     =&gt;   Ext.form.DateField
+      #   :numberfield   =&gt;   Ext.form.NumberField
+      #   :radio         =&gt;   Ext.form.Radio
+      #   :textarea      =&gt;   Ext.form.TextArea
+      #   :textfield     =&gt;   Ext.form.TextField
+      #   :timefield     =&gt;   Ext.form.TimeField
+      # 
       def add(name=nil, data=nil, options={})
         options[:header] = name if name
-        options[:dataIndex] = data if data
+        options[:dataIndex] = data if date
+        
+        if options[:editor]
+          xtype = options[:editor].delete(:xtype)
+          case xtype
+            when :checkbox    then options.delete(:editor); options.merge!(:checkbox =&gt; true)
+            when :combo       then options.merge!(:editor =&gt; l(&quot;new Ext.form.ComboBox(#{Configuration.new(options[:editor]).to_s(3)})&quot;))
+            when :datefield   then options.merge!(:editor =&gt; l(&quot;new Ext.form.DateField(#{Configuration.new(options[:editor]).to_s(3)})&quot;))
+            when :numberfield then options.merge!(:editor =&gt; l(&quot;new Ext.form.NumberField(#{Configuration.new(options[:editor]).to_s(3)})&quot;))
+            when :radio       then options.merge!(:editor =&gt; l(&quot;new Ext.form.Radio(#{Configuration.new(options[:editor]).to_s(3)})&quot;))
+            when :textarea    then options.merge!(:editor =&gt; l(&quot;new Ext.form.TextArea(#{Configuration.new(options[:editor]).to_s(3)})&quot;))
+            when :textfield   then options.merge!(:editor =&gt; l(&quot;new Ext.form.TextField(#{Configuration.new(options[:editor]).to_s(3)})&quot;))
+            when :timefield   then options.merge!(:editor =&gt; l(&quot;new Ext.form.TimeField(#{Configuration.new(options[:editor]).to_s(3)})&quot;))
+          end
+        end
+        
         case options[:renderer]
           when :date        then options.merge!(:renderer =&gt; l(&quot;Ext.util.Format.dateRenderer()&quot;))
           when :datetime    then options.merge!(:renderer =&gt; l(&quot;Ext.util.Format.dateTimeRenderer()&quot;))
@@ -66,7 +111,9 @@ module Lipsiadmin
           when :us_money    then options.merge!(:renderer =&gt; l(&quot;Ext.util.Format.usMoney&quot;))
           when :boolean     then options.merge!(:renderer =&gt; l(&quot;Ext.util.Format.boolRenderer&quot;))
         end
-        raise ComponentError, &quot;You must provide header and dataIndex for generate a column model&quot; if options[:header].blank? || options[:dataIndex].blank?
+        
+        raise ComponentError, &quot;You must provide header and dataIndex for generate a column model&quot; if options[:header].blank? || 
+                                                                                                     options[:dataIndex].blank?
         config[:columns] &lt;&lt; Configuration.new(options)
       end
     end</diff>
      <filename>lib/view/helpers/ext/column_model.rb</filename>
    </modified>
    <modified>
      <diff>@@ -38,10 +38,22 @@ module Lipsiadmin
     #     grid.bbar  :store =&gt; grid.get_store, :pageSize =&gt; params[:limit]
     #   end
     # 
+    #   # Returns:
+    #   #   var grid = new Ext.grid.EditorGridPanel({
+    #   #     clicksToEdit: 1,
+    #   #   ...
+    #
+    #   page.grid :editable =&gt; true do |grid|
+    #     grid.id &quot;grid-posts&quot;
+    #     ...
+    # 
     class Grid &lt; Component
+
       def initialize(options={}, &amp;block)#:nodoc:
         # Call Super Class for initialize configuration
-        super(&quot;Ext.grid.GridPanel&quot;, options)
+        @editable = options.delete(:editable)
+        
+        super(&quot;Ext.grid.#{@editable ? 'EditorGridPanel' : 'GridPanel' }&quot;, options)
 
         # Write default configuration if not specified
         config[:plugins]      ||= []
@@ -255,7 +267,7 @@ module Lipsiadmin
         end
         
         if @default_tbar
-          after &lt;&lt; render_javascript(:grid_functions, :var =&gt; get_var, :store =&gt; config[:store], :sm =&gt; config[:sm], :tbar =&gt; config[:tbar])
+          after &lt;&lt; render_javascript(:grid_functions, :var =&gt; get_var, :store =&gt; config[:store], :sm =&gt; config[:sm], :tbar =&gt; config[:tbar], :editable =&gt; @editable)
         end
         
         if config[:store]</diff>
      <filename>lib/view/helpers/ext/grid.rb</filename>
    </modified>
    <modified>
      <diff>@@ -13,6 +13,56 @@
    }
 });
 
+&lt;% if @editable %&gt;
+&lt;%= @var %&gt;.on('cellmousedown', function(grid, rowIndex, colIndex, e){
+  var columnId  = grid.getColumnModel().getColumnId(colIndex);
+  var column    = grid.getColumnModel().getColumnById(columnId);
+  var t         = e.getTarget();
+
+  if(column.checkbox &amp;&amp; t.className &amp;&amp; t.className.indexOf('x-grid3-cc-'+t.id) != -1){
+    e.stopEvent();
+    var record    = grid.store.getAt(rowIndex);
+    var editEvent = {
+      grid: grid,
+      record: grid.store.getAt(rowIndex),
+      field: column.dataIndex,
+      value: !record.data[column.dataIndex],
+      originalValue: record.data[column.dataIndex],
+      row: rowIndex,
+      column: grid.getColumnModel().findColumnIndex(column.dataIndex)
+    };
+    record.set(column.dataIndex, editEvent.value);
+    grid.getSelectionModel().selectRow(rowIndex);
+    grid.fireEvent('afteredit', editEvent);
+  }
+});
+
+
+&lt;%= @var %&gt;.on('afteredit', function(e){
+  var columnId  = &lt;%= @var %&gt;.getColumnModel().getColumnId(e.column);
+  var column    = &lt;%= @var %&gt;.getColumnModel().getColumnById(columnId);
+
+  Ext.Ajax.request({
+    url: '&lt;%= @base_path %&gt;/'+e.record.id,
+    method: 'PUT',
+    params: column.name+'='+e.value,
+    success: function(result, request){
+      var resultValue = Ext.decode(result.responseText); 
+      if (resultValue.success == true){
+        e.record.commit();
+      } else {
+        Ext.MessageBox.alert(Lipsiadmin.locale.alert.title, resultValue.msg);
+        e.record.reject();
+      }
+    },                
+    failure: function(result, request) {
+      Ext.Msg.alert(Lipsiadmin.locale.alert.title, Lipsiadmin.locale.alert.msg);
+      e.record.reject();
+    }
+  });
+});
+&lt;% end %&gt;
+
 function add(){
   Backend.app.load('&lt;%= @new_path.blank? ? &quot;#{@base_path}/new&quot; : @new_path %&gt;');
 }</diff>
      <filename>lib/view/helpers/ext/templates/grid_functions.js.erb</filename>
    </modified>
    <modified>
      <diff>@@ -141,8 +141,8 @@ module Lipsiadmin
         #     grid.bbar  :store =&gt; grid.get_store, :pageSize =&gt; params[:limit]
         #   end
         # 
-        def grid(&amp;block)
-          self &lt;&lt; Lipsiadmin::Ext::Grid.new(&amp;block)
+        def grid(options={}, &amp;block)
+          self &lt;&lt; Lipsiadmin::Ext::Grid.new(options, &amp;block)
         end
       end
     end</diff>
      <filename>lib/view/helpers/ext_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -30,6 +30,7 @@ Backend.app = function(){
           contentEl:'header',
           region:'north',
           border: false,
+          height: 65,
           bbar: new Ext.Toolbar({ cls:'x-toolbar-menu', items: [&lt;%= backend_menu %&gt;] })
         });
       }
@@ -61,12 +62,16 @@ Backend.app = function(){
       return window.location.search ? Ext.urlDecode(window.location.search.substring(1)).small : false;
     }, // small
     
+    toolbar: function(){
+      return window.location.search ? Ext.urlDecode(window.location.search.substring(1)).toolbar : false;
+    }, // hideToolbar
+    
     load : function(url, cache){
       var ext = (/[.]/.exec(url)) ? /[^.]+$/.exec(url) : 'html';
       var cache = (cache &amp;&amp; cache == true) || false;
       
       if (!cache){ Backend.cache.clear(); }
-      
+
       if (ext.length == 1 &amp;&amp; ext[0].toLowerCase() == 'js') {
         // Clean the cache
         this.clean();
@@ -81,10 +86,11 @@ Backend.app = function(){
           } 
         });
       } else if (ext == 'html'){
-        this.contentDynamic.getUpdater().update({ url: url, headers: { 'Accept': 'text/html, text/javascript, application/xml, text/xml, */*' } });
+        this.contentDynamic.getUpdater().update({ url: url, scripts: false, headers: { 'Accept': 'text/html, text/javascript, application/xml, text/xml, */*' } });
       } else {
         Ext.Msg.alert(Backend.locale.messages.alert.title, Backend.locale.messages.alert.message);
       }
+      this.contentDynamic.addEvents('inspection');
     }, // load
     
     back: function(){
@@ -106,6 +112,7 @@ Backend.app = function(){
     clean : function(){
       this.mask();
       this.contentDynamic.body.update('');
+      this.contentDynamic.items.each(function(i){ i.destroy(); });
       this.contentDynamic.removeAll(true);
       this.contentDynamic.doLayout();
     }, // clean
@@ -113,9 +120,6 @@ Backend.app = function(){
     addItem : function(item){
       this.contentDynamic.add(item);
       this.contentDynamic.doLayout();
-      if (this.smallView()){
-        window.parent.Backend.window.item = item;
-      }
     }, // addItem
     
     submitForm : function(){
@@ -148,7 +152,12 @@ Backend.app = function(){
       if (tabs.elements.length &gt; 0){
         // Build Tabs
         var items = tabs.elements.collect(function(tab){
-          return { id: tab.id, contentEl: tab.id, title: tab.title };
+          var editable = tab.getAttribute('htmleditor');
+          if (editable) {
+            return { id: tab.id, autoScroll:false, title: tab.title, items: { xtype: 'htmleditor', id: editable, enableFont: false, value: tab.getAttribute('value') } };
+          } else {
+            return { id: tab.id, contentEl: tab.id, title: tab.title };
+          }
         });
 
         // Get ActiveTab
@@ -156,29 +165,69 @@ Backend.app = function(){
         
         // Get The container, this code is redundant, but is a trick for ie.
         var container = Ext.get(tabs.elements[0].id).parent().id;
-
-        // Build TabPanel
-        var tabPanel = new Ext.TabPanel({
+        
+        var tabConfig = {
           applyTo: container,
           layoutOnTabChange:true,
           activeTab: activeTab,
           border:false,
           region:'center',
           items: items,
-          bbar: [{ 
-            text: Backend.locale.buttons.back, 
-            cls: 'x-btn-text-icon back', 
-            handler: Backend.app.back 
-          }, '-&gt;',{ 
-            text: Backend.locale.buttons.save, 
-            cls: 'x-btn-text-icon save', 
-            handler: Backend.app.submitForm 
-          }],
           defaults: { autoScroll:true, layout:'fit' }
-        });
+        }
         
+        if (this.toolbar()!=&quot;1&quot;){
+          Ext.apply(tabConfig, {
+            bbar: [{ 
+              text: Backend.locale.buttons.back, 
+              cls: 'x-btn-text-icon back', 
+              handler: Backend.app.back 
+            }, '-&gt;',{ 
+              text: Backend.locale.buttons.save, 
+              cls: 'x-btn-text-icon save', 
+              handler: Backend.app.submitForm 
+            }]
+          });
+        }
+
+        // Build TabPanel
+        var tabPanel = new Ext.TabPanel(tabConfig);
         this.addItem(tabPanel);
+        // Need to use this because some times we add tabs from inline scripts
+        tabPanel.on('add', function(){ tabPanel.setActiveTab(activeTab) });
+      }
+      
+      // Now we can load scripts
+      var html = el.dom.innerHTML;
+      var id = Ext.id();
+      var dom = this.contentDynamic.body.dom;
+      
+      var hd = document.getElementsByTagName(&quot;head&quot;)[0];
+      var re = /(?:&lt;script([^&gt;]*)?&gt;)((\n|\r|.)*?)(?:&lt;\/script&gt;)/ig;
+      var srcRe = /\ssrc=([\'\&quot;])(.*?)\1/i;
+      var typeRe = /\stype=([\'\&quot;])(.*?)\1/i;
+
+      var match;
+      while(match = re.exec(html)){
+        var attrs = match[1];
+        var srcMatch = attrs ? attrs.match(srcRe) : false;
+        if(srcMatch &amp;&amp; srcMatch[2]){
+          var s = document.createElement(&quot;script&quot;);
+          s.src = srcMatch[2];
+          var typeMatch = attrs.match(typeRe);
+          if(typeMatch &amp;&amp; typeMatch[2]){
+            s.type = typeMatch[2];
+          }
+          hd.appendChild(s);
+        }else if(match[2] &amp;&amp; match[2].length &gt; 0){
+          if(window.execScript) {
+            window.execScript(match[2]);
+          } else {
+            window.eval(match[2]);
+          }
+        }
       }
+      
       this.unmask();
     },//inspectContent
     
@@ -267,63 +316,64 @@ Backend.app = function(){
   } // return
 }();
 
-Backend.window = function(){
-  return {
-    current: undefined, // currentWindow
-    item: undefined, // item
-    config: undefined, // config
-    open: function(config){
-      if (this.current) { this.current.close(); }
-      this.config = config;
-      this.current = new Ext.Window({
-        width: 700,
-        height: 300,
-        layout: 'fit',
-        autoScroll: true,
-        modal: true,
-        resizable: true,
-        maximizable: true,
-        bodyStyle: 'background-color:#FFF',
-        buttons:[{
-          text: Backend.locale.buttons.close,
-          handler: this.close
-        },{
-          text: Backend.locale.buttons.select,
-          handler: this.select
-        }],
-        html: '&lt;iframe id=&quot;'+Ext.id('','iframe-')+'&quot; src=&quot;/backend/base/?small=1&amp;load='+config.url+'&quot; frameBorder=&quot;0&quot; width=&quot;100%&quot; height=&quot;100%&quot; /&gt;'
-      });
-      this.current.show();
-      return this.current
-    }, // open
-    
-    close: function(){
-      if (Backend.window.current){
-        Backend.window.current.close();
-        Backend.window.item   = undefined;
-        Backend.window.config = undefined;
-      }
-    }, // close
-    
-    select: function(){
-      try {
-        var selected =  Backend.window.item.getSelectionModel().getSelected();
-        var config   =  Backend.window.config;
-        var name = selected.data[config.display];
-        if (config.value=='id'){
-          var id = selected.id;
-        } else {
-          var id = selected.data[config.value];
-        }
-        $(config.displayField).update(name);
-        $(config.valueField).value = id;
-        Backend.window.close();
-      } catch(e) {
-        Ext.Msg.alert(Backend.locale.messages.alert.title, Backend.locale.messages.alert.notSelected);
-      }
-    } // select
-  } // return
-}();
+Backend.window = Ext.extend(Ext.Window, {
+  width: 700,
+  height: 300,
+  layout: 'fit',
+  autoScroll: true,
+  modal: true,
+  maximizable: true,
+  bodyStyle: 'background-color:#FFF',
+  grid: undefined,
+  form: false,
+  url: '',
+  iframeId: Ext.id('','iframe-'),
+  initComponent : function(){
+    Backend.window.superclass.initComponent.call(this);
+    this.addEvents('selected');
+    this.addEvents('saved');
+    this.addButton({
+      text: Backend.locale.buttons.close,
+      handler: this[this.closeAction].createDelegate(this, [])      
+    });
+    if (this.grid){
+      this.addButton({
+        text: Backend.locale.buttons.select,
+        handler: this.closeWithSelections.createDelegate(this, [])}
+      );
+    }
+    if (this.form){
+      this.addButton({
+        text: Backend.locale.buttons.save,
+        handler: this.saveForm.createDelegate(this, [])}
+      );
+    }
+    this.html = '&lt;iframe id=&quot;'+this.iframeId+'&quot; src=&quot;/backend/base/?small=1&amp;toolbar='+(this.form?1:0)+'&amp;load='+this.url+'&quot; frameBorder=&quot;0&quot; width=&quot;100%&quot; height=&quot;100%&quot; /&gt;';
+  }, // initComponent
+  
+  afterShow : function(afterShow){
+    Backend.window.superclass.afterShow.call(this);
+    this.contentWindow = Ext.fly(this.iframeId).dom.contentWindow;
+  }, // onRender
+  
+  getSelections: function(){
+    return this.contentWindow[this.grid].getSelectionModel().getSelections();
+  }, // getSelections
+  
+  closeWithSelections: function(){
+    if (this.getSelections().length &gt; 0){
+      this.fireEvent('selected', this, this.getSelections());
+      this[this.closeAction]();
+    } else { 
+      Ext.Msg.alert(Backend.locale.messages.alert.title, Backend.locale.messages.alert.notSelected); 
+    }
+  }, // closeWithSelections
+  
+  saveForm: function(){
+    this.contentWindow.Backend.app.submitForm();
+    this.fireEvent('saved', this);
+  } // saveForm
+});
 
 Backend.cache = function(){
   return {</diff>
      <filename>lipsiadmin_generators/backend/templates/views/javascripts/backend.js.erb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>aa587f161e7eab0f80eab0ef65ef92a7c87b2704</id>
    </parent>
  </parents>
  <author>
    <name>Davide D'Agostino</name>
    <email>DAddYE@DAddYE.local</email>
  </author>
  <url>http://github.com/Lipsiasoft/lipsiadmin/commit/93abc345b0c1ce0c4239e096a8716adaefc91799</url>
  <id>93abc345b0c1ce0c4239e096a8716adaefc91799</id>
  <committed-date>2009-05-11T07:19:44-07:00</committed-date>
  <authored-date>2009-05-11T07:19:44-07:00</authored-date>
  <message>  * Bumped version to 4.0.0
  * Added editable grids
  * Refactored backend.js so javascript in tabs are evalued after render so you can interact with tabs
  * Refactored Backend.window so now you can do much more with your grids/forms. See rdoc for examples.
  * Small refactor to attachment processor, now original attachments are saved without &quot;_original_&quot; in the filename.</message>
  <tree>ce8811abd1a3a020ff4a2c27c59685f486272c0f</tree>
  <committer>
    <name>Davide D'Agostino</name>
    <email>DAddYE@DAddYE.local</email>
  </committer>
</commit>
