app/components/panda/cms/rich_text_component.rb in panda-cms-0.7.0 vs app/components/panda/cms/rich_text_component.rb in panda-cms-0.7.2

- old
+ new

@@ -33,52 +33,163 @@ block_content = block.block_contents.find_by(panda_cms_page_id: Current.page.id) if block_content.nil? block_content = Panda::CMS::BlockContent.create!( block: block, panda_cms_page_id: Current.page.id, - content: "" + content: empty_editor_js_content ) end - @content = block_content.cached_content || block_content.content - raise ComponentError, "No content found for block: #{block.id}" if @content.nil? - + raw_content = block_content.cached_content || block_content.content + @content = raw_content.presence || empty_editor_js_content @options[:id] = block_content.id + # Debug log the content + Rails.logger.debug("RichTextComponent content before processing: #{@content.inspect}") + if @editable @options[:data] = { page_id: Current.page.id, mode: "rich_text" } - # Convert HTML content to EditorJS format if needed - begin - editor_content = Panda::CMS::HtmlToEditorJsConverter.convert(@content) - @content = editor_content - rescue Panda::CMS::HtmlToEditorJsConverter::ConversionError => e - raise ComponentError, "Failed to convert content: #{e.message}" + # For editable mode, always ensure we have a valid EditorJS structure + @content = if @content.blank? || @content == "{}" + empty_editor_js_content + else + begin + if @content.is_a?(String) + # Try to parse as JSON first + begin + parsed = JSON.parse(@content) + if valid_editor_js_content?(parsed) + # Ensure the content is properly structured + { + "time" => parsed["time"] || Time.current.to_i * 1000, + "blocks" => parsed["blocks"].map { |block| + { + "type" => block["type"], + "data" => block["data"].merge( + "text" => block["data"]["text"].to_s.presence || "" + ), + "tunes" => block["tunes"] + }.compact + }, + "version" => parsed["version"] || "2.28.2" + } + else + # If not valid EditorJS, try to convert from HTML + begin + editor_content = Panda::CMS::HtmlToEditorJsConverter.convert(@content) + if valid_editor_js_content?(editor_content) + editor_content + else + empty_editor_js_content + end + rescue Panda::CMS::HtmlToEditorJsConverter::ConversionError => e + Rails.logger.error("HTML conversion error: #{e.message}") + empty_editor_js_content + end + end + rescue JSON::ParserError => e + Rails.logger.error("JSON parse error: #{e.message}") + # Try to convert from HTML + begin + editor_content = Panda::CMS::HtmlToEditorJsConverter.convert(@content) + if valid_editor_js_content?(editor_content) + editor_content + else + empty_editor_js_content + end + rescue Panda::CMS::HtmlToEditorJsConverter::ConversionError => e + Rails.logger.error("HTML conversion error: #{e.message}") + empty_editor_js_content + end + end + else + # If it's not a string, assume it's already in the correct format + valid_editor_js_content?(@content) ? @content : empty_editor_js_content + end + rescue => e + Rails.logger.error("Content processing error: #{e.message}\nContent: #{@content.inspect}") + empty_editor_js_content + end end - elsif @content.is_a?(Hash) - begin - renderer = Panda::CMS::EditorJs::Renderer.new(@content) - @content = renderer.render - rescue => e - raise ComponentError, "Failed to render content: #{e.message}" - end else - @content = @content.html_safe + # For non-editable mode, handle content display + @content = if @content.blank? || @content == "{}" + "<p></p>".html_safe + else + begin + # Try to parse as JSON if it looks like EditorJS format + if @content.is_a?(String) && @content.strip.match?(/^\{.*"blocks":\s*\[.*\].*\}$/m) + parsed_content = JSON.parse(@content) + if valid_editor_js_content?(parsed_content) + # Check if it's just an empty paragraph + if parsed_content["blocks"].length == 1 && + parsed_content["blocks"][0]["type"] == "paragraph" && + parsed_content["blocks"][0]["data"]["text"].blank? + "<p></p>".html_safe + else + renderer = Panda::CMS::EditorJs::Renderer.new(parsed_content) + rendered = renderer.render + rendered.presence&.html_safe || "<p></p>".html_safe + end + else + process_html(@content) + end + else + process_html(@content) + end + rescue JSON::ParserError + process_html(@content) + rescue => e + Rails.logger.error("RichTextComponent render error: #{e.message}\nContent: #{@content.inspect}") + "<p></p>".html_safe + end + end end rescue ActiveRecord::RecordNotFound => e raise ComponentError, "Database record not found: #{e.message}" rescue ActiveRecord::RecordInvalid => e raise ComponentError, "Invalid record: #{e.message}" rescue => e - raise ComponentError, "Component error: #{e.message}" + Rails.logger.error("RichTextComponent error: #{e.message}\nContent: #{@content.inspect}") + @content = @editable ? empty_editor_js_content : "<p></p>".html_safe + nil end + private + + def empty_editor_js_content + { + time: Time.current.to_i * 1000, + blocks: [{type: "paragraph", data: {text: ""}}], + version: "2.28.2" + } + end + + def valid_editor_js_content?(content) + content.is_a?(Hash) && content["blocks"].is_a?(Array) && content["version"].present? + rescue + false + end + + def process_html(content) + return "<p></p>".html_safe if content.blank? + + # If it's already HTML, just return it + if content.match?(/<[^>]+>/) + content.html_safe + else + # Wrap plain text in paragraph tags + "<p>#{content}</p>".html_safe + end + end + # Only render the component if there is some content set, or if the component is editable def render? - @content.present? || @editable + true # Always render, we'll show empty content if needed end end end end