mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -05:00
clean up onebox application so it uses a single code path
use fragments for oneboxes strip parent <p> if <div> is in it clean some tests
This commit is contained in:
parent
ab9c55689e
commit
33e3ad1603
6 changed files with 90 additions and 29 deletions
|
@ -243,15 +243,11 @@ class Post < ActiveRecord::Base
|
||||||
# If we have any of the oneboxes in the cache, throw them in right away, don't
|
# If we have any of the oneboxes in the cache, throw them in right away, don't
|
||||||
# wait for the post processor.
|
# wait for the post processor.
|
||||||
dirty = false
|
dirty = false
|
||||||
doc = Oneboxer.each_onebox_link(cooked) do |url, elem|
|
result = Oneboxer.apply(cooked) do |url, elem|
|
||||||
cached = Oneboxer.render_from_cache(url)
|
Oneboxer.render_from_cache(url)
|
||||||
if cached.present?
|
|
||||||
elem.swap(cached)
|
|
||||||
dirty = true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
cooked = doc.to_html if dirty
|
cooked = result.to_html if result.changed?
|
||||||
cooked
|
cooked
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ class CookedPostProcessor
|
||||||
@dirty = false
|
@dirty = false
|
||||||
@opts = opts
|
@opts = opts
|
||||||
@post = post
|
@post = post
|
||||||
@doc = Nokogiri::HTML(post.cooked)
|
@doc = Nokogiri::HTML::fragment(post.cooked)
|
||||||
@size_cache = {}
|
@size_cache = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -23,13 +23,10 @@ class CookedPostProcessor
|
||||||
args = {post_id: @post.id}
|
args = {post_id: @post.id}
|
||||||
args[:invalidate_oneboxes] = true if @opts[:invalidate_oneboxes]
|
args[:invalidate_oneboxes] = true if @opts[:invalidate_oneboxes]
|
||||||
|
|
||||||
Oneboxer.each_onebox_link(@doc) do |url, element|
|
result = Oneboxer.apply(@doc) do |url, element|
|
||||||
onebox, preview = Oneboxer.onebox(url, args)
|
Oneboxer.onebox(url, args)
|
||||||
if onebox
|
|
||||||
element.swap onebox
|
|
||||||
@dirty = true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@dirty ||= result.changed?
|
||||||
end
|
end
|
||||||
|
|
||||||
# First let's consider the images
|
# First let's consider the images
|
||||||
|
@ -127,6 +124,10 @@ class CookedPostProcessor
|
||||||
@doc.try(:to_html)
|
@doc.try(:to_html)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def doc
|
||||||
|
@doc
|
||||||
|
end
|
||||||
|
|
||||||
def get_size(url)
|
def get_size(url)
|
||||||
return nil unless SiteSetting.crawl_images? || url.start_with?(Discourse.base_url)
|
return nil unless SiteSetting.crawl_images? || url.start_with?(Discourse.base_url)
|
||||||
@size_cache[url] ||= FastImage.size(url)
|
@size_cache[url] ||= FastImage.size(url)
|
||||||
|
|
|
@ -10,6 +10,16 @@ Dir["#{Rails.root}/lib/oneboxer/*_onebox.rb"].each {|f|
|
||||||
module Oneboxer
|
module Oneboxer
|
||||||
extend Oneboxer::Base
|
extend Oneboxer::Base
|
||||||
|
|
||||||
|
Result = Struct.new(:doc, :changed) do
|
||||||
|
def to_html
|
||||||
|
doc.to_html
|
||||||
|
end
|
||||||
|
|
||||||
|
def changed?
|
||||||
|
changed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
Dir["#{Rails.root}/lib/oneboxer/*_onebox.rb"].sort.each do |f|
|
Dir["#{Rails.root}/lib/oneboxer/*_onebox.rb"].sort.each do |f|
|
||||||
add_onebox "Oneboxer::#{Pathname.new(f).basename.to_s.gsub(/\.rb$/, '').classify}".constantize
|
add_onebox "Oneboxer::#{Pathname.new(f).basename.to_s.gsub(/\.rb$/, '').classify}".constantize
|
||||||
end
|
end
|
||||||
|
@ -66,7 +76,7 @@ module Oneboxer
|
||||||
# Parse URLs out of HTML, returning the document when finished.
|
# Parse URLs out of HTML, returning the document when finished.
|
||||||
def self.each_onebox_link(string_or_doc)
|
def self.each_onebox_link(string_or_doc)
|
||||||
doc = string_or_doc
|
doc = string_or_doc
|
||||||
doc = Nokogiri::HTML(doc) if doc.is_a?(String)
|
doc = Nokogiri::HTML::fragment(doc) if doc.is_a?(String)
|
||||||
|
|
||||||
onebox_links = doc.search("a.onebox")
|
onebox_links = doc.search("a.onebox")
|
||||||
if onebox_links.present?
|
if onebox_links.present?
|
||||||
|
@ -80,6 +90,32 @@ module Oneboxer
|
||||||
doc
|
doc
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.apply(string_or_doc)
|
||||||
|
doc = string_or_doc
|
||||||
|
doc = Nokogiri::HTML::fragment(doc) if doc.is_a?(String)
|
||||||
|
changed = false
|
||||||
|
|
||||||
|
Oneboxer.each_onebox_link(doc) do |url, element|
|
||||||
|
onebox, preview = yield(url,element)
|
||||||
|
if onebox
|
||||||
|
parsed_onebox = Nokogiri::HTML::fragment(onebox)
|
||||||
|
next unless parsed_onebox.children.count > 0
|
||||||
|
|
||||||
|
# special logic to strip empty p elements
|
||||||
|
if element.parent &&
|
||||||
|
element.parent.node_name.downcase == "p" &&
|
||||||
|
element.parent.children.count == 1 &&
|
||||||
|
parsed_onebox.children.first.name.downcase == "div"
|
||||||
|
element = element.parent
|
||||||
|
end
|
||||||
|
changed = true
|
||||||
|
element.swap parsed_onebox.to_html
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Result.new(doc, changed)
|
||||||
|
end
|
||||||
|
|
||||||
def self.cache_key_for(url)
|
def self.cache_key_for(url)
|
||||||
"onebox:#{Digest::SHA1.hexdigest(url)}"
|
"onebox:#{Digest::SHA1.hexdigest(url)}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,19 +3,19 @@ require 'spec_helper'
|
||||||
require 'cooked_post_processor'
|
require 'cooked_post_processor'
|
||||||
|
|
||||||
describe CookedPostProcessor do
|
describe CookedPostProcessor do
|
||||||
let :cpp do
|
|
||||||
|
def cpp(cooked = nil, options = {})
|
||||||
post = Fabricate.build(:post_with_youtube)
|
post = Fabricate.build(:post_with_youtube)
|
||||||
|
post.cooked = cooked if cooked
|
||||||
post.id = 123
|
post.id = 123
|
||||||
CookedPostProcessor.new(post)
|
CookedPostProcessor.new(post, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'process_onebox' do
|
context 'process_onebox' do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
post = Fabricate.build(:post_with_youtube)
|
@cpp = cpp(nil, invalidate_oneboxes: true)
|
||||||
post.id = 123
|
Oneboxer.expects(:onebox).with("http://www.youtube.com/watch?v=9bZkp7q19f0", post_id: 123, invalidate_oneboxes: true).returns('<div>GANGNAM STYLE</div>')
|
||||||
@cpp = CookedPostProcessor.new(post, invalidate_oneboxes: true)
|
|
||||||
Oneboxer.expects(:onebox).with("http://www.youtube.com/watch?v=9bZkp7q19f0", post_id: 123, invalidate_oneboxes: true).returns('GANGNAM STYLE')
|
|
||||||
@cpp.post_process_oneboxes
|
@cpp.post_process_oneboxes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -23,15 +23,13 @@ describe CookedPostProcessor do
|
||||||
@cpp.should be_dirty
|
@cpp.should be_dirty
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'inserts the onebox' do
|
it 'inserts the onebox without wrapping p' do
|
||||||
@cpp.html.should == <<EXPECTED
|
@cpp.html.should match_html "<div>GANGNAM STYLE</div>"
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
|
||||||
<html><body>GANGNAM STYLE</body></html>
|
|
||||||
EXPECTED
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
context 'process_images' do
|
context 'process_images' do
|
||||||
|
|
||||||
it "has no topic image if there isn't one in the post" do
|
it "has no topic image if there isn't one in the post" do
|
||||||
|
|
|
@ -159,7 +159,7 @@ describe Oneboxer do
|
||||||
element.is_a?(Nokogiri::XML::Element).should be_true
|
element.is_a?(Nokogiri::XML::Element).should be_true
|
||||||
url.should == 'http://discourse.org'
|
url.should == 'http://discourse.org'
|
||||||
end
|
end
|
||||||
result.kind_of?(Nokogiri::HTML::Document).should be_true
|
result.kind_of?(Nokogiri::HTML::DocumentFragment).should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'yields each url and element when given a doc' do
|
it 'yields each url and element when given a doc' do
|
||||||
|
@ -172,5 +172,35 @@ describe Oneboxer do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "apply_onebox" do
|
||||||
|
it "is able to nuke wrapping p" do
|
||||||
|
doc = Oneboxer.apply "<p><a href='http://bla.com' class='onebox'>bla</p>" do |url, element|
|
||||||
|
"<div>foo</div>" if url == "http://bla.com"
|
||||||
|
end
|
||||||
|
|
||||||
|
doc.changed? == true
|
||||||
|
doc.to_html.should match_html "<div>foo</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is able to do nothing if nil is returned" do
|
||||||
|
orig = "<p><a href='http://bla.com' class='onebox'>bla</p>"
|
||||||
|
doc = Oneboxer.apply orig do |url, element|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
doc.changed? == false
|
||||||
|
doc.to_html.should match_html orig
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not strip if there is a br in same node" do
|
||||||
|
doc = Oneboxer.apply "<p><br><a href='http://bla.com' class='onebox'>bla</p>" do |url, element|
|
||||||
|
"<div>foo</div>" if url == "http://bla.com"
|
||||||
|
end
|
||||||
|
|
||||||
|
doc.changed? == true
|
||||||
|
doc.to_html.should match_html "<p><br><div>foo</div></p>"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ Fabricator(:post) do
|
||||||
end
|
end
|
||||||
|
|
||||||
Fabricator(:post_with_youtube, from: :post) do
|
Fabricator(:post_with_youtube, from: :post) do
|
||||||
cooked '<a href="http://www.youtube.com/watch?v=9bZkp7q19f0" class="onebox" target="_blank">http://www.youtube.com/watch?v=9bZkp7q19f0</a>'
|
cooked '<p><a href="http://www.youtube.com/watch?v=9bZkp7q19f0" class="onebox" target="_blank">http://www.youtube.com/watch?v=9bZkp7q19f0</a></p>'
|
||||||
end
|
end
|
||||||
|
|
||||||
Fabricator(:old_post, from: :post) do
|
Fabricator(:old_post, from: :post) do
|
||||||
|
@ -75,4 +75,4 @@ Fabricator(:private_message_post, from: :post) do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
raw "Ssshh! This is our secret conversation!"
|
raw "Ssshh! This is our secret conversation!"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue