require 'uri' # Used to get a list of the assets and other included components # from the dependencies.rb files. module Volt class AssetFiles def self.from_cache(component_name, component_paths) # @cache ||= {} # @cache[component_name] ||= begin # not cached, create self.new(component_name, component_paths) # end end def initialize(component_name, component_paths) @component_paths = component_paths @assets = [] @included_components = {} @components = [] @disable_auto_import = [] # Include each of the default included components Volt.config.default_components.each do |def_comp_name| component(def_comp_name) end component(component_name) end def disable_auto_import @disable_auto_import.push(*@current_component).uniq end def load_dependencies(path, component_name) if path dependencies_file = File.join(path, 'config/dependencies.rb') else fail "Unable to find component #{component_name.inspect}" end if File.exist?(dependencies_file) # Run the dependencies file in this asset files context code = File.read(dependencies_file) @current_component = component_name instance_eval(code, dependencies_file, 0) end end def component(name) unless @included_components[name] # Track that we added @included_components[name] = true # Get the path to the component component_path = @component_paths.component_paths(name) unless component_path fail "Unable to find component '#{name}', make sure the gem is included in your Gemfile" end component_path.each do |path| # Load the dependencies load_dependencies(path, name) # Add any assets add_assets(path) unless @disable_auto_import.include?(name) @components << [path, name] end end end # Called when you want to add a gem to the opal load path so it can be # required on the client side. def opal_gem(gem_name) Opal.use_gem(gem_name) Opal.paths.uniq! # require(gem_name) end def components @included_components.keys end def javascript_file(locator) @assets << [:javascript_file, prepare_locator(locator, ['js'])] end def css_file(locator) @assets << [:css_file, prepare_locator(locator, ['css','scss'])] end def prepare_locator(locator, valid_extensions) unless url_or_path?(locator) locator = File.join('/assets', @current_component, '/assets', valid_extensions.first, "#{locator}") locator += '.css' unless locator =~ /^.*\.(#{valid_extensions.join('|')})$/ end locator end def url_or_path?(url) (url =~ URI::regexp || url =~ /^\/(\/)?.*/) ? true : false end def component_paths @components end def add_assets(path) asset_folder = File.join(path, 'assets') @assets << [:folder, asset_folder] if File.directory?(asset_folder) end def javascript_files(*args) fail "Deprecation: #javascript_files is deprecated in config/base/index.html, opal 0.8 required a new format. For an updated config/base/index.html file, see https://gist.github.com/ryanstout/0858cf7dfc32c514f790" end def css_files(*args) fail "Deprecation: #css_files is deprecated in config/base/index.html, opal 0.8 required a new format. For an updated config/base/index.html file, see https://gist.github.com/ryanstout/0858cf7dfc32c514f790" end # Returns script tags that should be included def javascript_tags(volt_app) @opal_tag_generator ||= Opal::Server::Index.new(nil, volt_app.opal_files.server) javascript_files = [] @assets.each do |type, path| case type when :folder # for a folder, we search for all .js files and return a tag for them javascript_files += Dir["#{path}/**/*.js"].sort.map { |folder| '/assets' + folder[path.size..-1] } when :javascript_file # javascript_file is a cdn path to a JS file javascript_files << path end end javascript_files = javascript_files.uniq scripts = javascript_files.map {|url| "" } # Include volt itself. Unless we are running with MAPS=all, just include # the main file without sourcemaps. volt_path = 'volt/volt/app' if ENV['MAPS'] == 'all' scripts << @opal_tag_generator.javascript_include_tag(volt_path) else scripts << "" scripts << "" end scripts << @opal_tag_generator.javascript_include_tag('components/main') scripts.join("\n") end # Returns the link tags for the css def css_tags css.map do |url| "" end.join("\n") end # Returns an array of all css files that should be included. def css css_files = [] @assets.each do |type, path| case type when :folder # Don't import any css/scss files that start with an underscore, so scss partials # aren't imported by default: # http://sass-lang.com/guide css_files += Dir["#{path}/**/[^_]*.{css,scss}"].sort.map do |folder| '/assets' + folder[path.size..-1].gsub(/[.]scss$/, '') end when :css_file css_files << path end end css_files.uniq end # #javascript is only used on the server unless RUBY_PLATFORM == 'opal' # Parses the javascript tags to reutrn the following: # [[:url, '/somefile.js'], [:body, 'var inlinejs = true;']] def javascript(volt_app) javascript_tags(volt_app) .scan(/[<]script([^>]*)[>](.*?)[<]\/script[^>]*[>]/) .map do |attrs, body| src = attrs.match(/[\s|$]src\s*[=]\s*["']([^"']+?)["']/) if src [:src, src[1]] else [:body, body] end end end end end end