module DashcodeConverter CSS_IMAGE_URL_REGEX= /url\("?(.*\.(jpg|png|gif))"?\)/ BUNDLE_EXTENSION= "jsnib" class Project attr_accessor :namespace def initialize(project_bundle, output_folder) @project_bundle= File.expand_path(project_bundle) @name= File.basename(@project_bundle, ".*") @namespace= @name @output_folder= File.expand_path(File.join(output_folder, "#{@name}.#{BUNDLE_EXTENSION}")) @parts_spec_path= File.join(@project_bundle, "project", "safari", "Parts", "setup.js") @datasources_spec_path= File.join(@project_bundle, "project", "Parts", "datasources.js") @css_path= File.join(@project_bundle, "project", "safari", "main.css") @markup_path= File.join(@project_bundle, "project", "index.html") @images_folder= File.join(@output_folder, "images") FileUtils.mkdir_p(@output_folder) end def path_relative_to_folder(path, folder) path= File.expand_path(path) outputFolder= File.expand_path(folder).to_s # Remove leading slash and split into parts file_parts= path.slice(1..-1).split('/'); output_parts= outputFolder.slice(1..-1).split('/'); common_prefix_length= 0 file_parts.each_index { |i| common_prefix_length= i break if file_parts[i]!=output_parts[i] } return '../'*(output_parts.length-common_prefix_length) + file_parts[common_prefix_length..-1].join('/') end def relative_path(path) path_relative_to_folder(path, @output_folder) end def doc return @doc if @doc html= File.read(@markup_path) @doc= Nokogiri::HTML(html) end def controller return @controller if @controller @controller= Controller.new(@name, @namespace) end def nib return @nib if @nib @nib= Nib::Nib.new(@name, controller) @nib.add_view_from_path(@parts_spec_path) @nib.add_datasources_from_path(@datasources_spec_path) @nib end def css text= File.read(@css_path) dirname= File.dirname(@css_path) text.gsub!(CSS_IMAGE_URL_REGEX) { |match| image_file= File.join(dirname, $1) if (!File.exists?(image_file)) match else new_image_file= File.join(@images_folder, File.basename(image_file)) FileUtils.mkdir_p(File.dirname(new_image_file)) FileUtils.cp image_file, new_image_file "url(\"#{relative_path(new_image_file)}\")" end } text end def fixup_html base= doc.css("base") base= base ? base.attribute("href") : nil content= doc.css("body > *:first-child")[0] content.traverse { |node| next unless node.attributes node.attributes.each { |attr, value| if 0==attr.index("apple-") node.remove_attribute(attr) end } } dirname= File.dirname(@markup_path) dirname= File.join(dirname, base) if base content.css("[src]").each { |node| image_file= File.join(dirname, node.attribute('src')) new_image_file= File.join(@images_folder, File.basename(image_file)) FileUtils.mkdir_p(File.dirname(new_image_file)) FileUtils.cp image_file, new_image_file node["src"]= relative_path(new_image_file) } nib.views.each { |view| # Use a copy of the view's items, because the iterator isn't stable if # items are removed while iterating. items= view.items.clone items.each { |item| html= doc.css(item.name)[0] item.fixup_html(html) } } end def convert fixup_html FileUtils.mkdir_p(@output_folder) FileUtils.mkdir_p(@images_folder) Dir.chdir(@output_folder) do File.open("#{@name.capitalize}Controller.js", "w") { |controller_file| controller_file << controller.declaration } File.open("#{@name}.js", "w") { |nib_file| nib_file << nib.declaration } File.open("#{@name}.css", "w") { |css_file| css_file << css } File.open("#{@name}.html", "w") { |html_file| html_file << doc.css("body > *:first-child")[0].serialize } end end end end