Created
March 14, 2013 20:03
-
-
Save jondkinney/5164703 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rack/utils' | |
require 'nokogiri' | |
class HtmlDemo | |
include Rack::Utils | |
def initialize(app, opts = {}) | |
@app = app | |
@opts = { | |
:element_id => 'page', | |
:local_save_dir => 'public/shots', | |
:public_save_dir => 'public/demos' | |
} | |
@opts.merge! opts | |
end | |
def call(env) | |
status, headers, response = @app.call(env) | |
headers = HeaderHash.new(headers) | |
if !STATUS_WITH_NO_ENTITY_BODY.include?(status) && | |
!headers['transfer-encoding'] && | |
headers['content-type'] && | |
headers['content-type'].include?('text/html') | |
#&& headers['record-demo'] == 'true' | |
content = '' | |
response.each { |part| content += part } | |
doc = Nokogiri::HTML(content, nil, 'UTF-8') | |
body = doc.to_html | |
user_id = env['rack.session']['user_id'] | |
# removing this for now so that we can have demos span across users | |
#if user_id | |
# current_user = User.find(user_id) | |
# save_dir = "#{@opts[:local_save_dir]}/user_#{current_user.id}" | |
#else | |
save_dir = "#{@opts[:local_save_dir]}" | |
#end | |
response_params = env['action_dispatch.request.parameters'] | |
if response_params | |
if response_params['record'] && response_params['record'] == 'true' | |
# ensure directory exists | |
FileUtils.mkdir_p("#{save_dir}") | |
files = Dir.entries("#{save_dir}") - ['.','..'] | |
file_number = files.length + 1 | |
if file_number < 10 | |
file_number = "0#{file_number}" | |
end | |
filename = "#{file_number}_#{response_params['controller'].gsub(/\//,'_')}_#{response_params['action']}.html" | |
# write html template file | |
File.open("#{save_dir}/#{filename}", 'w') { |f| f.write(body) } | |
elsif response_params['new_demo'] && response_params['new_demo'] == 'true' && user_id | |
FileUtils.rm_r(Dir.glob("#{save_dir}/*")) unless Dir["#{save_dir}"].empty? | |
end | |
if demo_name = response_params['new_html_demo_name'] | |
demo_dir = "#{@opts[:public_save_dir]}/#{demo_name}" | |
FileUtils.mkdir_p(demo_dir) | |
FileUtils.cp_r("#{save_dir}/.", demo_dir) | |
files = Dir.entries(demo_dir) - ['.','..'] | |
sorted = files.sort { |a,b| a.split('.')[0].split('_')[0] <=> b.split('.')[0].split('_')[0] } | |
sorted.each_with_index do |file,index| | |
if index+1 < sorted.length | |
next_filename = sorted[index+1] | |
else | |
next_filename = '#' | |
end | |
full_file = "#{demo_dir}/#{file}" | |
doc = Nokogiri::HTML(open(full_file), nil, 'utf-8') | |
#Remove elements we don't want in the HTML demos | |
doc.css('div#html_demo_controls').remove | |
doc.css('div#google_analytics').remove | |
doc.css('div#get_clicky_user_voice').remove | |
doc.css('div#footer_version').remove | |
doc.css('#html_demo_controls_handle').remove | |
# Add a starting html page with a link to the first file so we can | |
# just refer to the demo by name | |
if index == 0 | |
starting_html_page = doc.dup | |
node = starting_html_page.css('div#content > .wrapper').first | |
node.children.remove | |
link_node = Nokogiri::XML::Node.new('a',starting_html_page) | |
link_node['href'] = "#{file}" | |
link_node['class'] = 'button orange' | |
link_node.content = 'Start Demo' | |
node.add_child(link_node) | |
node['style'] = 'margin:50px auto;width:116px;' | |
File.open("#{demo_dir}/index.html", 'w') { |f| f.write(starting_html_page.to_html) } | |
end | |
elements = doc.css('form') + doc.css('a') | |
leave_elements = doc.css('.firm_modal_click') + doc.css('.cancel_modal') | |
elements = elements - leave_elements | |
elements.each do |element| | |
if element.attributes['action'] | |
element.attributes['action'].value = next_filename | |
elsif element.attributes['href'] | |
if next_filename == '#' | |
element['data-prevent-default'] = 'true' | |
end | |
element.attributes['href'].value = next_filename | |
end | |
# ensure a get request | |
if element.attributes['method'] | |
element.attributes['method'].value = 'get' | |
end | |
if element.attributes['data-method'] | |
element.attributes['data-method'].remove | |
end | |
end | |
# remove iframes since we will want to replace them with our own custom content (a real screenshot most likely) | |
if doc.css('iframe').first | |
doc.css('iframe').first['src'] = '/docusign_placeholder.html' | |
end | |
# Give us back the Bolstr logo as a link back to the real application | |
if logo = doc.css('h1#logo_backlink > a').first | |
logo['href'] = '/' | |
logo['data-prevent-default'] = 'false' | |
logo['data-no-turbolink'] = 'true' | |
end | |
# adjust the stylesheet and javascript tags to point to the non | |
# minified/gzipped/asset pipelined version so that between | |
# deploys on staging the demos saved to the shared folder will | |
# continue to work | |
doc.css('.app_stylesheet').each_with_index do |element, i| | |
if i > 0 | |
element.remove | |
else | |
if element.attributes['href'] | |
element.attributes['href'].value = '/assets/application.css' | |
end | |
end | |
end | |
doc.css('.app_javascript').each_with_index do |element, i| | |
if i > 0 | |
element.remove | |
else | |
if element.attributes['src'] | |
element.attributes['src'].value = '/assets/application.js' | |
end | |
end | |
end | |
File.open(full_file, 'w') { |f| f.write(doc) } | |
end | |
[301, {'Location' => '/demos'}, self] | |
else #no demo name given, but a screenshot might have been taken | |
[status, headers, [body]] | |
end | |
else #no screenshot params passed | |
[status, headers, [body]] | |
end | |
else | |
[status, headers, response] | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment