CultivateLabs / storytime

Storytime is a Rails 4+ CMS and blogging engine, with a core focus on content. It is built and maintained by @cultivatelabs
MIT License
752 stars 81 forks source link

Doesn’t support video embeds? #158

Closed drwpow closed 9 years ago

drwpow commented 9 years ago

Hi there—if this is not a real issue then please remove. But when I go to copy + paste an iframe / embed script (YouTube or Vimeo), it works fine in the preview, but as soon as the post is updated it all gets stripped out of the content. How can I prevent this from happening?

Inserting embed code screen shot 2015-05-03 at 6 51 45 pm

Still there when I switch back to rich text mode screen shot 2015-05-03 at 6 51 56 pm

On “Update,” it’s all gone screen shot 2015-05-03 at 6 52 17 pm

eanlain commented 9 years ago

That's due to Storytime.post_sanitizer which is called when a post is saved. post_sanitizer is just a hook to handle post content sanitization (i.e. which tags and HTML attributes to allow and/or disallow in a post). By default, the following Proc block is called and used to sanitize the content:

# lib/storytime.rb
@@post_sanitizer = Proc.new do |draft_content|
  white_list_sanitizer = if Rails::VERSION::MINOR <= 1
    HTML::WhiteListSanitizer.new
  else
    Rails::Html::WhiteListSanitizer.new
  end

  attributes = %w(
    id class href style src title width height alt value 
    target rel align disabled name
  )

  white_list_sanitizer.sanitize(draft_content, attributes: attributes)
end

You can override this in your Storytime config file (config/initializers/storytime.rb) and handle post sanitization anyway you'd like (or not at all if you desire).

If you're just trying to add the iframe tag, and the frameborder and allowfullscreen attributes you should be able to use the following:

# config/initializers/storytime.rb

# Hook for handling post content sanitization.
# Accepts either a Lambda or Proc which can be used to
# handle how post content is sanitized (i.e. which tags,
# HTML attributes to allow/disallow.
config.post_sanitizer = Proc.new do |draft_content|
  white_list_sanitizer = if Rails::VERSION::MINOR <= 1
    HTML::WhiteListSanitizer.new
  else
    Rails::Html::WhiteListSanitizer.new
  end

  if Rails::VERSION::MINOR <= 1
    tags = white_list_sanitizer.allowed_tags
  else
    tags = Loofah::HTML5::WhiteList::ALLOWED_ELEMENTS_WITH_LIBXML2
  end

  tags.add("iframe")

  attributes = %w(
    id class href style src title width height alt value 
    target rel align disabled name frameborder allowfullscreen
  )

  white_list_sanitizer.sanitize(draft_content, tags: tags, attributes: attributes)
end

If you'd just like to allow any content (no sanitization) you can just use the following:

# config/initializers/storytime.rb

# Hook for handling post content sanitization.
# Accepts either a Lambda or Proc which can be used to
# handle how post content is sanitized (i.e. which tags,
# HTML attributes to allow/disallow.
config.post_sanitizer = Proc.new do |draft_content|
  # No need to sanitize content, just passing it through...
  draft_content
end

Let me know if this helps.

eanlain commented 9 years ago

I'm sure others will run into this at some point, so I'll add a wiki entry expounding on post sanitation.

Thanks!

drwpow commented 9 years ago

Perfect. Much appreciated! Figured something like that was occurring.

eanlain commented 9 years ago

A slightly better version than what I originally posted that uses the defaults of the Rails sanitizers in use, and adds the "iframe" tag and "frameborder" and "allowfullscreen" attributes.

# Host app: config/initializers/storytime.rb

config.post_sanitizer = Proc.new do |draft_content|
  if Rails::VERSION::MINOR <= 1
    white_list_sanitizer = HTML::WhiteListSanitizer.new
    tags = white_list_sanitizer.allowed_tags
    attributes = white_list_sanitizer.allowed_attributes
  else
    white_list_sanitizer = Rails::Html::WhiteListSanitizer.new
    tags = Loofah::HTML5::WhiteList::ALLOWED_ELEMENTS_WITH_LIBXML2
    attribtues = Loofah::HTML5::WhiteList::ALLOWED_ATTRIBUTES
  end

  # Add any additional tags or attributes to tags/attributes Sets here.
  tags.add("iframe")
  attributes.merge(["frameborder", "allowfullscreen"])

  white_list_sanitizer.sanitize(draft_content, tags: tags, attributes: attributes)
end
drwpow commented 9 years ago

Interesting. This gives me a lot to play around with. Thanks again, @eanlain!