From 0b2a6935a2b72b9a017f2766a30822c62ac54da7 Mon Sep 17 00:00:00 2001 From: Jacques Distler Date: Fri, 23 Jan 2009 11:02:16 -0600 Subject: [PATCH] Export XHTML Pages When a Web uses one of the Markdown Text Filters, and you export all the pages as a zip file, you'd like the MathML and SVG to render when the pages are viewed locally. This means saving them with a .xhtml extension. Users of non-XHTML-capable browsers or Textile users should still get .html files. --- app/controllers/application.rb | 8 +++--- app/controllers/wiki_controller.rb | 24 ++++++++++++---- lib/chunks/chunk.rb | 4 +-- lib/chunks/literal.rb | 4 +-- lib/url_generator.rb | 6 ++-- test/functional/wiki_controller_test.rb | 38 +++++++++++++++++++++++-- 6 files changed, 64 insertions(+), 20 deletions(-) diff --git a/app/controllers/application.rb b/app/controllers/application.rb index d0dc37f6..95b6a2b4 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -172,6 +172,10 @@ class ApplicationController < ActionController::Base end end + def xhtml_enabled? + in_a_web? and (@web.markup == :markdownMML or @web.markup == :markdownPNG or @web.markup == :markdown) + end + protected def set_robots_metatag @@ -200,10 +204,6 @@ class ApplicationController < ActionController::Base not @web_name.nil? end - def xhtml_enabled? - in_a_web? and (@web.markup == :markdownMML or @web.markup == :markdownPNG or @web.markup == :markdown) - end - def authorization_needed? not %w( login authenticate feeds published atom_with_headlines atom_with_content).include?(action_name) end diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index b068c401..5df3ee56 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -68,7 +68,7 @@ class WikiController < ApplicationController def export_html stylesheet = File.read(File.join(RAILS_ROOT, 'public', 'stylesheets', 'instiki.css')) - export_pages_as_zip('html') do |page| + export_pages_as_zip(html_ext) do |page| renderer = PageRenderer.new(page.revisions.last) rendered_page = <<-EOL @@ -90,6 +90,10 @@ class WikiController < ApplicationController +

+ #{@web.name}
+ #{page.plain_name} +

#{renderer.display_content_for_export}
#{page.revisions? ? "Revised" : "Created" } on #{ page.revised_at.strftime('%B %d, %Y %H:%M:%S') } @@ -329,6 +333,15 @@ class WikiController < ApplicationController end end + def html_ext + if xhtml_enabled? && request.env.include?('HTTP_ACCEPT') && + Mime::Type.parse(request.env["HTTP_ACCEPT"]).include?(Mime::XHTML) + 'xhtml' + else + 'html' + end + end + protected def do_caching? @@ -364,7 +377,7 @@ class WikiController < ApplicationController end def export_pages_as_zip(file_type, &block) - + file_prefix = "#{@web.address}-#{file_type}-" timestamp = @web.revised_at.strftime('%Y-%m-%d-%H-%M-%S') file_path = File.join(@wiki.storage_path, file_prefix + timestamp + '.zip') @@ -376,9 +389,9 @@ class WikiController < ApplicationController zip_out.puts(block.call(page)) end # add an index file, if exporting to HTML - if file_type.to_s.downcase == 'html' - zip_out.put_next_entry 'index.html' - zip_out.puts "" + + if file_type.to_s.downcase == html_ext + zip_out.put_next_entry "index.#{html_ext}" + zip_out.puts "" + "" end end @@ -468,5 +481,4 @@ class WikiController < ApplicationController end end - end diff --git a/lib/chunks/chunk.rb b/lib/chunks/chunk.rb index 02b2eb9a..9b32d55f 100644 --- a/lib/chunks/chunk.rb +++ b/lib/chunks/chunk.rb @@ -61,7 +61,7 @@ module Chunk end def unmask - @content.sub!(/#{mask}/){|s| s.replace @unmask_text} + @content.sub!(mask){|s| s.replace @unmask_text} end def rendered? @@ -73,7 +73,7 @@ module Chunk end def revert - @content.sub!(/#{mask}/){|s| s.replace @text} + @content.sub!(mask){|s| s.replace @text} # unregister @content.delete_chunk(self) end diff --git a/lib/chunks/literal.rb b/lib/chunks/literal.rb index c53e7477..a345a041 100644 --- a/lib/chunks/literal.rb +++ b/lib/chunks/literal.rb @@ -24,7 +24,7 @@ module Literal # A literal chunk that protects HTML tags from wiki rendering. class Tags < AbstractLiteral - TAGS_PATTERN = Regexp.new('<[-a-zA-Z]+[^>]*?>', Regexp::MULTILINE) + TAGS_PATTERN = Regexp.new(']*?>', Regexp::MULTILINE) def self.pattern() TAGS_PATTERN end end @@ -32,7 +32,7 @@ module Literal class Math < AbstractLiteral MATH_START = '(\${1,2}|' + Regexp.escape('\[') + '|\\begin\{equation\})' MATH_END = '(\${1,2}|' + Regexp.escape('\]') + '|\\end\{equation\})' - MATH_PATTERN = Regexp.new(MATH_START + '([^$]|\\\$)+?' + MATH_END, Regexp::MULTILINE) + MATH_PATTERN = Regexp.new(MATH_START + '([^$]|\\\$)+' + MATH_END, Regexp::MULTILINE) def self.pattern() MATH_PATTERN end end diff --git a/lib/url_generator.rb b/lib/url_generator.rb index 7bddc24e..690d1b2b 100644 --- a/lib/url_generator.rb +++ b/lib/url_generator.rb @@ -52,7 +52,7 @@ class UrlGenerator < AbstractUrlGenerator case mode when :export if known_file - %{#{text}} + %{#{text}} else %{#{text}} end @@ -79,7 +79,7 @@ class UrlGenerator < AbstractUrlGenerator case mode when :export if known_page - %{#{text}} + %{#{text}} else %{#{text}} end @@ -142,5 +142,5 @@ class UrlGenerator < AbstractUrlGenerator %{[[#{name}:delete]]} end end - + end diff --git a/test/functional/wiki_controller_test.rb b/test/functional/wiki_controller_test.rb index 5721faa6..d7f867ef 100755 --- a/test/functional/wiki_controller_test.rb +++ b/test/functional/wiki_controller_test.rb @@ -111,7 +111,39 @@ class WikiControllerTest < Test::Unit::TestCase assert_equal '/wiki1/save/With+%3A+Special+%2F%3E+symbols', form.attributes['action'] end + def test_export_xhtml + @request.accept = 'application/xhtml+xml' + # rollback homepage to a version that is easier to match + @home.rollback(0, Time.now, 'Rick', test_renderer) + r = process 'export_html', 'web' => 'wiki1' + + assert_response(:success, bypass_body_parsing = true) + assert_equal 'application/zip', r.headers['type'] + assert_match /attachment; filename="wiki1-xhtml-\d\d\d\d-\d\d-\d\d-\d\d-\d\d-\d\d.zip"/, + r.headers['Content-Disposition'] + assert_equal 'PK', r.body[0..1], 'Content is not a zip file' + + # Tempfile doesn't know how to open files with binary flag, hence the two-step process + Tempfile.open('instiki_export_file') { |f| @tempfile_path = f.path } + begin + File.open(@tempfile_path, 'wb') { |f| f.write(r.body); @exported_file = f.path } + Zip::ZipFile.open(@exported_file) do |zip| + assert_equal %w(Elephant.xhtml FirstPage.xhtml HomePage.xhtml MyWay.xhtml NoWikiWord.xhtml Oak.xhtml SmartEngine.xhtml ThatWay.xhtml index.xhtml), zip.dir.entries('.').sort + assert_match /.*/, + zip.file.read('Elephant.xhtml').gsub(/\s+/, ' ') + assert_match /.*/, + zip.file.read('Oak.xhtml').gsub(/\s+/, ' ') + assert_match /.*/, + zip.file.read('HomePage.xhtml').gsub(/\s+/, ' ') + assert_equal ' ', zip.file.read('index.xhtml').gsub(/\s+/, ' ') + end + ensure + File.delete(@tempfile_path) if File.exist?(@tempfile_path) + end + end + def test_export_html + @request.accept = 'tex/html' # rollback homepage to a version that is easier to match @home.rollback(0, Time.now, 'Rick', test_renderer) r = process 'export_html', 'web' => 'wiki1' @@ -134,19 +166,19 @@ class WikiControllerTest < Test::Unit::TestCase zip.file.read('Oak.html').gsub(/\s+/, ' ') assert_match /.*/, zip.file.read('HomePage.html').gsub(/\s+/, ' ') - assert_equal ' ', zip.file.read('index.html').gsub(/\s+/, ' ') + assert_equal ' ', zip.file.read('index.html').gsub(/\s+/, ' ') end ensure File.delete(@tempfile_path) if File.exist?(@tempfile_path) end end - + def test_export_html_no_layout r = process 'export_html', 'web' => 'wiki1', 'layout' => 'no' assert_response(:success, bypass_body_parsing = true) assert_equal 'application/zip', r.headers['type'] - assert_match /attachment; filename="wiki1-html-\d\d\d\d-\d\d-\d\d-\d\d-\d\d-\d\d.zip"/, + assert_match /attachment; filename="wiki1-x?html-\d\d\d\d-\d\d-\d\d-\d\d-\d\d-\d\d.zip"/, r.headers['Content-Disposition'] assert_equal 'PK', r.body[0..1], 'Content is not a zip file' end