2009-02-11 4 views
8

Tôi có một trang sẽ liệt kê các tin bài. Để giảm độ dài của trang, tôi chỉ muốn hiển thị quảng cáo xem trước (200 từ đầu tiên/600 chữ cái của bài viết) và sau đó hiển thị liên kết "thêm ...", khi được nhấp, sẽ mở rộng phần còn lại của bài viết theo cách jQuery/Javascript. Bây giờ, tôi đã tìm ra và thậm chí tìm thấy phương pháp trợ giúp sau trên một số trang dán, điều này sẽ đảm bảo rằng bài viết (chuỗi) không được cắt nhỏ ngay giữa một từ:đường ray: nhận một lời trêu ghẹo/đoạn trích cho một bài viết

def shorten (string, count = 30) 
    if string.length >= count 
     shortened = string[0, count] 
     splitted = shortened.split(/\s/) 
     words = splitted.length 
     splitted[0, words-1].join(" ") + ' ...' 
    else 
     string 
    end 
    end 

Vấn đề mà tôi có là các cơ quan bài viết tin tức mà tôi nhận được từ DB được định dạng HTML. Vì vậy, nếu tôi không may mắn, trình trợ giúp ở trên sẽ cắt chuỗi bài viết của tôi ngay ở giữa thẻ html và chèn chuỗi "thêm ..." vào đó (ví dụ: "" giữa), sẽ làm hỏng html của tôi trên trang .

Có cách nào xung quanh việc này hoặc có một plugin nào ở đó mà tôi có thể sử dụng để tạo trích đoạn/quảng cáo xem trước từ chuỗi HTML không?

Trả lời

2

Cảm ơn rất nhiều câu trả lời của bạn! Tuy nhiên, trong khi chờ đợi, tôi tình cờ gặp jQuery HTML Truncator plugin, điều này hoàn toàn phù hợp với mục đích của tôi và thay đổi sự cắt xén thành phía máy khách.Nó không nhận được bất kỳ dễ dàng hơn :-)

1

bạn sẽ phải viết một trình phân tích cú pháp phức tạp hơn nếu bạn không muốn tách ở giữa các phần tử html. nó sẽ phải nhớ nếu nó đang ở giữa một khối <> và nếu nó giữa hai thẻ.

ngay cả khi bạn đã làm điều đó, bạn vẫn sẽ gặp sự cố. nếu một số đưa toàn bộ bài viết vào một phần tử html, vì trình phân tích cú pháp không thể phân chia nó ở bất kỳ đâu, vì thẻ đóng bị thiếu.

nếu có thể, tôi sẽ cố gắng không đặt bất kỳ thẻ nào vào bài viết hoặc giữ thẻ vào thẻ không chứa bất kỳ thứ gì (không có <div> v.v.). theo cách đó, bạn sẽ chỉ phải kiểm tra xem bạn có đang ở giữa một thẻ khá đơn giản không:

def shorten (string, count = 30) 
    if string.length >= count 
     shortened = string[0, count] 
     splitted = shortened.split(/\s/) 
     words = splitted.length 
     if(splitted[words-1].include? "<") 
     splitted[0,words-2].join(" ") + ' ...' 
     else 
     splitted[0, words-1].join(" ") + ' ...' 
    else 
     string 
    end 
    end 
3

My answer here sẽ hoạt động. Câu hỏi ban đầu (err, được hỏi bởi tôi) là về việc cắt bớt markdown, nhưng tôi đã kết thúc chuyển đổi markdown thành HTML sau đó cắt bớt nó, vì vậy nó sẽ làm việc. Tất nhiên nếu trang web của bạn nhận được nhiều lưu lượng truy cập, bạn nên cache đoạn trích (có lẽ khi bài đăng được tạo/cập nhật, bạn có thể lưu đoạn trích trong cơ sở dữ liệu?), Điều này cũng có nghĩa là bạn có thể cho phép người dùng sửa đổi hoặc nhập đoạn trích của mình

Cách sử dụng:

>> puts "<p><b><a href=\"hi\">Something</a></p>".truncate_html(5, at_end = "...") 
=> <p><b><a href="hi">Someth...</a></b></p> 

..và mã (sao chép từ câu trả lời khác):

require 'rexml/parsers/pullparser' 

class String 
    def truncate_html(len = 30, at_end = nil) 
    p = REXML::Parsers::PullParser.new(self) 
    tags = [] 
    new_len = len 
    results = '' 
    while p.has_next? && new_len > 0 
     p_e = p.pull 
     case p_e.event_type 
     when :start_element 
     tags.push p_e[0] 
     results << "<#{tags.last}#{attrs_to_s(p_e[1])}>" 
     when :end_element 
     results << "</#{tags.pop}>" 
     when :text 
     results << p_e[0][0..new_len] 
     new_len -= p_e[0].length 
     else 
     results << "<!-- #{p_e.inspect} -->" 
     end 
    end 
    if at_end 
     results << "..." 
    end 
    tags.reverse.each do |tag| 
     results << "</#{tag}>" 
    end 
    results 
    end 

    private 

    def attrs_to_s(attrs) 
    if attrs.empty? 
     '' 
    else 
     ' ' + attrs.to_a.map { |attr| %{#{attr[0]}="#{attr[1]}"} }.join(' ') 
    end 
    end 
end 
+0

oh tôi thích của bạn, nó khắc phục sự cố với các thẻ xung quanh văn bản – LDomagala

15

Bạn có thể sử dụng một sự kết hợp của 01.và Truncate.

truncate("And they found that many people were sleeping better.", 
    :omission => "... (continued)", :length => 15) 
# => And they found... (continued) 

Tôi đang thực hiện một tác vụ tương tự khi tôi có bài đăng trên blog và tôi chỉ muốn hiển thị đoạn trích nhanh. Vì vậy, theo quan điểm của tôi, tôi chỉ đơn giản là làm:

sanitize(truncate(blog_post.body, length: 150)) 

Đó là thẻ HTML đầu tiên, cung cấp cho tôi 150 ký tự đầu tiên và được xử lý trong chế độ xem sao cho MVC thân thiện.

Chúc may mắn!

+5

Điều này có thể hiệu quả, nhưng bạn nên vệ sinh và sau đó cắt bớt. Nếu bạn cắt ngắn và sau đó khử trùng, bạn có thể cắt ngắn ở giữa thẻ HTML và vệ sinh sẽ để lại một phần thẻ hiển thị. –

1

Tôi đã khử trùng HTML và trích xuất câu đầu tiên. Giả sử bạn có một mô hình bài báo, với một 'body' thuộc tính có chứa mã HTML:

# lib/core_ext/string.rb 
class String 
    def first_sentence 
    self[/(\A[^.|!|?]+)/, 1] 
    end 
end 

# app/models/article.rb 
def teaser 
    HTML::FullSanitizer.new.sanitize(body).first_sentence 
end 

này sẽ chuyển đổi "< b> Đây </b> là một < em> quan trọng </em> Bài viết Và! đây là phần còn lại của bài báo. " vào "Đây là một bài viết quan trọng".

+0

Chuỗi vá khỉ cho điều này là một chút quá mức ... – DGM

0

tôi giải quyết này sử dụng giải pháp sau

Cài đặt đá quý 'khử trùng'

gem install sanitize 

và sử dụng mã sau đây, đây cơ thể là văn bản có chứa các thẻ html.

<%= content_tag :div, Sanitize.clean(truncate(body, length: 200, separator: ' ', omission: "... #{ link_to '(continue)', '#' }"), Sanitize::Config::BASIC).html_safe %> 

Cung cấp trích đoạn có html hợp lệ. Tôi hy vọng nó giúp ai đó.

0

Bây giờ, có một viên ngọc có tên là HTMLTruncator để đảm bảo điều này cho bạn. Tôi đã sử dụng nó để hiển thị đoạn trích bài và những thứ tương tự, và nó rất mạnh mẽ.