Guest User

Chris

a guest
Jul 23rd, 2009
1,347
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 7.72 KB | None | 0 0
  1. module OpenDocumentCompressor
  2.  
  3.   private
  4.  
  5.   ODF_FILE_MIME_TYPES = {
  6.     "odt" => ["text",                  "Text Document"],
  7.     "odg" => ["graphics",              "Graphics document (Drawing)"],
  8.     "odp" => ["presentation",          "Presentation Document"],
  9.     "ods" => ["spreadsheet",           "Spreadsheet document"],
  10.     "odc" => ["chart",                 "Chart document"],
  11.     "odi" => ["image",                 "Image document"],
  12.     "odf" => ["formula",               "Formula document"],
  13.     "odm" => ["text-master",           "Global Text document"]
  14.   }
  15.  
  16.   ODF_TEMPLATE_MIME_TYPES = {
  17.     "ott" => ["text-template",         "Text document used as template"],
  18.     "oth" => ["text-web",              "Text document used as template for HTML documents"],
  19.     "otg" => ["graphics-template",     "Drawing document used as template"],
  20.     "otp" => ["presentation-template", "Presentation document used as template"],
  21.     "ots" => ["spreadsheet-template",  "Spreadsheet document used as template"],
  22.     "otc" => ["chart-template",        "Chart document used as template"],
  23.     "oti" => ["image-template",        "Image document used as template"],
  24.     "otf" => ["formula-template",      "Formula document used as template"]
  25.   }
  26.  
  27.   ODF_MIME_TYPES = ODF_FILE_MIME_TYPES.merge(ODF_TEMPLATE_MIME_TYPES)
  28.   ODF_MIME_TYPE_PREFIX = "application/vnd.oasis.opendocument"
  29.  
  30.   #in order to use this method efficiently, you must remember that everything in here is based on params[:format],
  31.   #so you should use this inside of respond_to do |format|
  32.  
  33.   #for example, if you would like to render .odp files (presentation) then you must do so like this
  34.   #step 1:
  35.   #   include this module in your application controller
  36.   #
  37.   #step 2; register the mimetype in config/initializers/mime_types.rb
  38.   #     for example, if you wish to use format.odp, you must register the odp mimetype like so:
  39.   #     Mime::Type.register "application/vnd.oasis.opendocument.presentation", :odp
  40.   #     if you want, you can use the constants in this module to register all the mime-types at once.
  41.   #     the key is the file extension, and the first value of the array is the type, it will go after application/vnd.oasis.opendocument. the loop may look something like this
  42.   #
  43.   #     OpenDocumentCompressor::ODF_MIME_TYPES.each do |key, value|
  44.   #       Mime::Type.register "application/vnd.oasis.opendocument.#{value[0]}", key
  45.   #     end
  46.   #
  47.   #step 3: build a respond_to block in the action you wish to have render dynamic odp content and call this method like so:
  48.   #    respond_to do |format|
  49.   #      format.odp {send_open_document_file}
  50.   #    end
  51.   #
  52.   #step 4: create a directory in app/views/layouts that is an EXACT replica of what you get when you unzip an opendocument file.
  53.   #   the best way to do that is to create a directory called app/views/layouts/odp and put and .odp file in there and unzip it.
  54.   #   you can test whether or not you have it right by calling the action you wish to export from your browser. you should get a file download dialogue,
  55.   #   and when you open the file, it should look the same as the one you used to create the layout directory.
  56.   #
  57.   #step 5: once you have your directory built properly, you must modify the files you wish to include dynamic content in as such
  58.   #   first, you must add a .erb file extension. (I use erb rather than builder here, simply because i don't want to have to port all the xml already in the files to the builder syntax)
  59.   #   second, figure out what parts of the file should be part of the layout, here's an example of my content.xml.erb file for my odp directory :
  60.   #   <?xml version="1.0" encoding="UTF-8"?>
  61.   #   <office:document-content office:version="1.2">
  62.   #     <office:scripts/>
  63.   #     <office:automatic-styles>
  64.   #       <%= yield :automatic_styles %>
  65.   #     </office:automatic-styles>
  66.   #     <office:body>
  67.   #       <office:presentation>
  68.   #         <%= yield %>
  69.   #       <presentation:settings presentation:mouse-visible="false"/>
  70.   #       </office:presentation>
  71.   #     </office:body>
  72.   #   </office:document-content>
  73.   #remember that yield will work in these files the same way they would in any other template you want to render.
  74.   # step 6;
  75.   #   now you need to create the template directories.
  76.   #   let's say you have a resource called Foo, and you wish to have the show action of this resource render an odp.
  77.   #   first you would need a directory named app/views/foos/odp/show
  78.   #   inside this directory, you MAY put a template file for each layout file you have in your layout directory. for example,
  79.   #   if you have a content.xml.erb file in your layout, you may have a content.xml.erb file in your template. if you do not, the layout will be rendered without any other content.
  80.   #
  81.   # please keep in mind that this code is very raw, and it will probably take some work on your part to make it work the way you want. if you have suggestions on how to improve this code, I'm all ears :)
  82.   # -C
  83.   # chris dot drappier at gmail dot com
  84.  
  85.   def send_open_document_file
  86.  
  87.     #create a temporary file to hold the archive.
  88.     t = Tempfile.new("template-for-#{params[:controller]}-#{params[:action]}-#{params[:format]}-#{request.remote_ip}")
  89.  
  90.     # Give the path of the temp file to the zip outputstream, it won't try to open it as an archive.
  91.     Zip::ZipOutputStream.open(t.path) do |zos|
  92.       Find.find("app/views/layouts/#{params[:format]}") do |layout_path|
  93.         basename = File.basename(layout_path)
  94.  
  95.         #ignore hidden files
  96.         if basename[0] == ?.
  97.           Find.prune
  98.         else
  99.           #this is the path that the layout file will live in once it's in the zip.
  100.           relative_path = layout_path.gsub(/^app\/views\/layouts\/#{params[:format]}\//, '')
  101.  
  102.           unless File.directory?(layout_path)
  103.             #start the next file in the zip.
  104.             zos.put_next_entry(relative_path.gsub(/\.erb$/, ''))
  105.  
  106.             #if the file is not an erb file, just read it in.
  107.             if !layout_path.match(/.*\.erb$/)
  108.               content = IO.read(layout_path)
  109.             else
  110.               content = openoffice_content(layout_path, basename)
  111.             end
  112.             zos.print content
  113.           end #eo unless FileTest.directory?(layout_path)
  114.         end #eo if basename[0] == ?.
  115.       end #eo Find.find
  116.     end #eo Zip::ZipOutputStream.open
  117.  
  118.     # End of the block  automatically closes the file.
  119.     # Send it using the right mime type, with a download window and some nice file name.
  120.     send_file t.path, :type => "#{ODF_MIME_TYPE_PREFIX}.#{ODF_MIME_TYPES[params[:format]]}", :disposition => 'attachment', :filename => "#{object.to_param}.#{params[:format]}"
  121.  
  122.     # The temp file will be deleted some time...
  123.     t.close
  124.   end
  125.  
  126.   #you may put a template file in the location specified here. for example:
  127.   #if you're trying to reach a resource located at http://localhost:3000/foo/1.odp
  128.   #then this will look for a directory called app/views/foo/odp/show to get the templates for each file in the final odp.
  129.   def openoffice_content(layout_path, basename)
  130.     template_path = "app/views/#{params[:controller]}/#{params[:format]}/#{params[:action]}/#{basename}"
  131.  
  132.     #each registered mime-type needs a template directory in app/views/layouts that corresponds to the mimetype. Example:
  133.     #the template for odp can be found in app/views/layouts/odp
  134.  
  135.     #if there's a template in the directory, render it with the layout. if there's not, just render the layout.
  136.     if File.exists?(template_path)
  137.       #for each file, evaluate the template code to a string
  138.       content = render_to_string(:template => template_path, :layout => layout_path)
  139.     else
  140.       content = render_to_string(:template => layout_path)
  141.     end
  142.     content
  143.   end
  144. end
Advertisement
Add Comment
Please, Sign In to add comment