FEATURE: added error messages for bad theme CSS / JS
This commit is contained in:
parent
3835e16cf7
commit
7eabb90b71
|
@ -75,6 +75,11 @@ export default Ember.Controller.extend({
|
|||
return fieldName && fieldName.indexOf("scss") > -1 ? "scss" : "html";
|
||||
},
|
||||
|
||||
@computed("currentTargetName", "fieldName", "saving")
|
||||
error(target, fieldName) {
|
||||
return this.get('model').getError(target, fieldName);
|
||||
},
|
||||
|
||||
@computed("fieldName", "currentTargetName")
|
||||
editorId(fieldName, currentTarget) {
|
||||
return fieldName + "|" + currentTarget;
|
||||
|
@ -139,7 +144,8 @@ export default Ember.Controller.extend({
|
|||
|
||||
actions: {
|
||||
save() {
|
||||
this.get('model').saveChanges("theme_fields");
|
||||
this.set('saving', true);
|
||||
this.get('model').saveChanges("theme_fields").finally(()=>{this.set('saving', false);});
|
||||
},
|
||||
|
||||
toggleMaximize: function() {
|
||||
|
|
|
@ -29,6 +29,15 @@ const Theme = RestModel.extend({
|
|||
}
|
||||
},
|
||||
|
||||
getError(target, name) {
|
||||
let themeFields = this.get("themeFields");
|
||||
let key = target + " " + name;
|
||||
console.log(themeFields);
|
||||
console.log(key);
|
||||
let field = themeFields[key];
|
||||
return field ? field.error : "";
|
||||
},
|
||||
|
||||
getField(target, name) {
|
||||
let themeFields = this.get("themeFields");
|
||||
let key = target + " " + name;
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
<div class='wrapper'>
|
||||
<h2>{{i18n 'admin.customize.theme.edit_css_html'}} {{#link-to 'adminCustomizeThemes.show' model.id replace=true}}{{model.name}}{{/link-to}}</h2>
|
||||
|
||||
{{#if error}}
|
||||
<pre class='field-error'>{{error}}</pre>
|
||||
{{/if}}
|
||||
|
||||
<div class='edit-main-nav'>
|
||||
<ul class='nav nav-pills target'>
|
||||
|
|
|
@ -7,6 +7,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.field-error {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
background-color: dark-light-diff($quaternary, $secondary, 70%, -70%);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.edit-main-nav {
|
||||
.nav-pills:after, .nav-pills:before {
|
||||
display: inline;
|
||||
|
|
|
@ -16,6 +16,8 @@ PLUGIN_API_JS
|
|||
end
|
||||
|
||||
def process_html(html)
|
||||
errors = nil
|
||||
|
||||
doc = Nokogiri::HTML.fragment(html)
|
||||
doc.css('script[type="text/x-handlebars"]').each do |node|
|
||||
name = node["name"] || node["data-template-name"] || "broken"
|
||||
|
@ -49,11 +51,13 @@ COMPILED
|
|||
node.replace("<script>#{code}</script>")
|
||||
rescue MiniRacer::RuntimeError => ex
|
||||
node.replace("<script type='text/discourse-js-error'>#{ex.message}</script>")
|
||||
errors ||= []
|
||||
errors << ex.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
doc.to_s
|
||||
[doc.to_s, errors&.join("\n")]
|
||||
end
|
||||
|
||||
|
||||
|
@ -61,16 +65,38 @@ COMPILED
|
|||
%w(body_tag head_tag header footer after_header)
|
||||
end
|
||||
|
||||
def self.scss_fields
|
||||
%w(scss embedded_scss)
|
||||
end
|
||||
|
||||
|
||||
def ensure_baked!
|
||||
if ThemeField.html_fields.include?(self.name)
|
||||
if !self.value_baked || compiler_version != COMPILER_VERSION
|
||||
|
||||
self.value_baked = process_html(self.value)
|
||||
self.value_baked, self.error = process_html(self.value)
|
||||
self.compiler_version = COMPILER_VERSION
|
||||
|
||||
if self.value_baked_changed? || compiler_version.changed?
|
||||
self.update_columns(value_baked: value_baked, compiler_version: compiler_version)
|
||||
if self.value_baked_changed? || compiler_version.changed? || self.error_changed?
|
||||
self.update_columns(value_baked: value_baked,
|
||||
compiler_version: compiler_version,
|
||||
error: error)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_scss_compiles!
|
||||
if ThemeField.scss_fields.include?(self.name)
|
||||
begin
|
||||
Stylesheet::Compiler.compile("@import \"theme_variables\"; @import \"theme_field\";",
|
||||
"theme.scss",
|
||||
theme_field: self.value.dup)
|
||||
self.error = nil unless error.nil?
|
||||
rescue SassC::SyntaxError => e
|
||||
self.error = e.message
|
||||
if error_changed?
|
||||
update_columns(error: self.error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -88,12 +114,13 @@ COMPILED
|
|||
|
||||
after_commit do
|
||||
ensure_baked!
|
||||
ensure_scss_compiles!
|
||||
|
||||
Stylesheet::Manager.clear_theme_cache! if self.name.include?("scss")
|
||||
|
||||
# TODO message for mobile vs desktop
|
||||
MessageBus.publish "/header-change/#{theme.key}", self.value if self.name == "header"
|
||||
MessageBus.publish "/footer-change/#{theme.key}", self.value if self.name == "footer"
|
||||
MessageBus.publish "/header-change/#{theme.key}", self.value if theme && self.name == "header"
|
||||
MessageBus.publish "/footer-change/#{theme.key}", self.value if theme && self.name == "footer"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class ThemeFieldSerializer < ApplicationSerializer
|
||||
attributes :name, :target, :value
|
||||
attributes :name, :target, :value, :error
|
||||
|
||||
def target
|
||||
case object.target
|
||||
|
@ -8,6 +8,10 @@ class ThemeFieldSerializer < ApplicationSerializer
|
|||
when 2 then "mobile"
|
||||
end
|
||||
end
|
||||
|
||||
def include_error?
|
||||
object.error.present?
|
||||
end
|
||||
end
|
||||
|
||||
class ChildThemeSerializer < ApplicationSerializer
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddErrorToThemeFields < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :theme_fields, :error, :string
|
||||
end
|
||||
end
|
|
@ -31,9 +31,8 @@ module Stylesheet
|
|||
end
|
||||
|
||||
def self.compile(stylesheet, filename, options={})
|
||||
|
||||
|
||||
source_map_file = options[:source_map_file] || "#{filename.sub(".scss","")}.css.map";
|
||||
|
||||
engine = SassC::Engine.new(stylesheet,
|
||||
importer: Importer,
|
||||
filename: filename,
|
||||
|
@ -41,6 +40,7 @@ module Stylesheet
|
|||
source_map_file: source_map_file,
|
||||
source_map_contents: true,
|
||||
theme_id: options[:theme_id],
|
||||
theme_field: options[:theme_field],
|
||||
load_paths: [ASSET_ROOT])
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@ module Stylesheet
|
|||
@special_imports[name] = blk
|
||||
end
|
||||
|
||||
register_import "theme_field" do
|
||||
Import.new("theme_field.scss", source: @theme_field)
|
||||
end
|
||||
|
||||
register_import "plugins" do
|
||||
import_files(DiscoursePluginRegistry.stylesheets)
|
||||
end
|
||||
|
@ -67,6 +71,7 @@ module Stylesheet
|
|||
|
||||
def initialize(options)
|
||||
@theme_id = options[:theme_id]
|
||||
@theme_field = options[:theme_field]
|
||||
end
|
||||
|
||||
def import_files(files)
|
||||
|
|
|
@ -125,7 +125,12 @@ class Stylesheet::Manager
|
|||
)
|
||||
rescue SassC::SyntaxError => e
|
||||
Rails.logger.error "Failed to compile #{@target} stylesheet: #{e.message}"
|
||||
[Stylesheet::Compiler.error_as_css(e, "#{@target} stylesheet"), nil]
|
||||
if %w{embedded_theme mobile_theme desktop_theme}.include?(@target.to_s)
|
||||
# no special errors for theme, handled in theme editor
|
||||
["", nil]
|
||||
else
|
||||
[Stylesheet::Compiler.error_as_css(e, "#{@target} stylesheet"), nil]
|
||||
end
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(cache_fullpath)
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ThemeField do
|
||||
it "correctly generates errors for transpiled js" do
|
||||
html = <<HTML
|
||||
<script type="text/discourse-plugin" version="0.8">
|
||||
badJavaScript(;
|
||||
</script>
|
||||
HTML
|
||||
field = ThemeField.create!(theme_id: 1, target: 0, name: "header", value: html)
|
||||
expect(field.error).not_to eq(nil)
|
||||
field.value = ""
|
||||
field.save!
|
||||
expect(field.error).to eq(nil)
|
||||
end
|
||||
|
||||
it "correctly generates errors for transpiled css" do
|
||||
css = "body {"
|
||||
field = ThemeField.create!(theme_id: 1, target: 0, name: "scss", value: css)
|
||||
field.reload
|
||||
expect(field.error).not_to eq(nil)
|
||||
field.value = ""
|
||||
field.save!
|
||||
expect(field.error).to eq(nil)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue