Use custom DiscourseSassImporter for site customization SCSS compilation.
This commit is contained in:
parent
ddd1dfe896
commit
df5ef38085
|
@ -1,3 +1,5 @@
|
||||||
|
require_dependency 'discourse_sass_importer'
|
||||||
|
|
||||||
class SiteCustomization < ActiveRecord::Base
|
class SiteCustomization < ActiveRecord::Base
|
||||||
ENABLED_KEY = '7e202ef2-56d7-47d5-98d8-a9c8d15e57dd'
|
ENABLED_KEY = '7e202ef2-56d7-47d5-98d8-a9c8d15e57dd'
|
||||||
# placing this in uploads to ease deployment rules
|
# placing this in uploads to ease deployment rules
|
||||||
|
@ -12,29 +14,13 @@ class SiteCustomization < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def compile_stylesheet(scss)
|
def compile_stylesheet(scss)
|
||||||
stylesheets_path = Rails.root.join('app', 'assets', 'stylesheets')
|
::Sass::Engine.new(scss, {
|
||||||
|
syntax: :scss,
|
||||||
# Get the sprockets environment. We need to do this because in production
|
cache: false,
|
||||||
# Rails.application.assets returns Sprockets::Index which does not compile
|
read_cache: false,
|
||||||
# assets.
|
style: :compressed,
|
||||||
sprockets = Rails.application.assets
|
filesystem_importer: DiscourseSassImporter
|
||||||
if sprockets.is_a?(Sprockets::Index)
|
}).render
|
||||||
sprockets = sprockets.instance_variable_get('@environment')
|
|
||||||
end
|
|
||||||
|
|
||||||
file_path = stylesheets_path.join('custom_stylesheet.scss')
|
|
||||||
|
|
||||||
File.open(file_path, 'w') do |f|
|
|
||||||
f.write scss
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
compiled = sprockets.find_asset('custom_stylesheet').body
|
|
||||||
ensure
|
|
||||||
FileUtils.rm file_path
|
|
||||||
end
|
|
||||||
|
|
||||||
compiled
|
|
||||||
end
|
end
|
||||||
|
|
||||||
before_save do
|
before_save do
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
# This custom importer is used for site customizations. This is similar to the
|
||||||
|
# Sprockets::SassImporter implementation provided in sass-rails since that is used
|
||||||
|
# during asset precompilation.
|
||||||
|
class DiscourseSassImporter < Sass::Importers::Filesystem
|
||||||
|
GLOB = /\*|\[.+\]/
|
||||||
|
|
||||||
|
def initialize(root)
|
||||||
|
@root = Rails.root.join('app', 'assets', 'stylesheets').to_s
|
||||||
|
@same_name_warnings = Set.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def extensions
|
||||||
|
{
|
||||||
|
'css' => :scss,
|
||||||
|
'css.scss' => :scss,
|
||||||
|
'css.sass' => :sass,
|
||||||
|
'css.erb' => :scss,
|
||||||
|
'scss.erb' => :scss,
|
||||||
|
'sass.erb' => :sass,
|
||||||
|
'css.scss.erb' => :scss,
|
||||||
|
'css.sass.erb' => :sass
|
||||||
|
}.merge!(super)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_relative(name, base, options)
|
||||||
|
if name =~ GLOB
|
||||||
|
glob_imports(name, Pathname.new(base), options)
|
||||||
|
else
|
||||||
|
engine_from_path(name, File.dirname(base), options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def find(name, options)
|
||||||
|
if name =~ GLOB
|
||||||
|
nil # globs must be relative
|
||||||
|
else
|
||||||
|
engine_from_path(name, root, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def each_globbed_file(glob, base_pathname, options)
|
||||||
|
Dir["#{base_pathname}/#{glob}"].sort.each do |filename|
|
||||||
|
next if filename == options[:filename]
|
||||||
|
yield filename # assume all matching files are requirable
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def glob_imports(glob, base_pathname, options)
|
||||||
|
contents = ""
|
||||||
|
each_globbed_file(glob, base_pathname.dirname, options) do |filename|
|
||||||
|
unless File.directory?(filename)
|
||||||
|
contents << "@import #{Pathname.new(filename).relative_path_from(base_pathname.dirname).to_s.inspect};\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil if contents.empty?
|
||||||
|
Sass::Engine.new(contents, options.merge(
|
||||||
|
filename: base_pathname.to_s,
|
||||||
|
importer: self,
|
||||||
|
syntax: :scss
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def engine_from_path(name, dir, options)
|
||||||
|
full_filename, syntax = Sass::Util.destructure(find_real_file(dir, name, options))
|
||||||
|
return unless full_filename && File.readable?(full_filename)
|
||||||
|
|
||||||
|
Sass::Engine.for_file(full_filename, options)
|
||||||
|
end
|
||||||
|
end
|
|
@ -155,12 +155,20 @@ describe SiteCustomization do
|
||||||
|
|
||||||
it 'should compile scss' do
|
it 'should compile scss' do
|
||||||
c = SiteCustomization.create!(user_id: user.id, name: "test", stylesheet: '$black: #000; #a { color: $black; }', header: '')
|
c = SiteCustomization.create!(user_id: user.id, name: "test", stylesheet: '$black: #000; #a { color: $black; }', header: '')
|
||||||
c.stylesheet_baked.should == "#a {\n color: black; }\n"
|
c.stylesheet_baked.should == "#a{color:#000}\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should compile mobile scss' do
|
it 'should compile mobile scss' do
|
||||||
c = SiteCustomization.create!(user_id: user.id, name: "test", stylesheet: '', header: '', mobile_stylesheet: '$black: #000; #a { color: $black; }', mobile_header: '')
|
c = SiteCustomization.create!(user_id: user.id, name: "test", stylesheet: '', header: '', mobile_stylesheet: '$black: #000; #a { color: $black; }', mobile_header: '')
|
||||||
c.mobile_stylesheet_baked.should == "#a {\n color: black; }\n"
|
c.mobile_stylesheet_baked.should == "#a{color:#000}\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should allow including discourse styles' do
|
||||||
|
c = SiteCustomization.create!(user_id: user.id, name: "test", stylesheet: '@import "desktop";', mobile_stylesheet: '@import "mobile";')
|
||||||
|
c.stylesheet_baked.should_not =~ /Syntax error/
|
||||||
|
c.stylesheet_baked.length.should > 1000
|
||||||
|
c.mobile_stylesheet_baked.should_not =~ /Syntax error/
|
||||||
|
c.mobile_stylesheet_baked.length.should > 1000
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should provide an awesome error on failure' do
|
it 'should provide an awesome error on failure' do
|
||||||
|
|
Loading…
Reference in New Issue