Pregunta

Tengo una página que lista los artículos de noticias.Para cortar hacia abajo en la página de longitud, sólo quiero mostrar un teaser (las primeras 200 palabras / 600 cartas del artículo) y, a continuación, mostrar un "más...", la que, cuando se hace clic, se expanda al resto del artículo en jQuery/Javascript manera.Ahora, todo lo que he averiguado y aún encontrado el siguiente método auxiliar en un poco de pasta de página, que se asegurará de que el artículo de las noticias (la cadena) no está cortado a la derecha en el medio de una palabra:

 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

El problema que tengo es que el artículo de las noticias de los cuerpos que puedo obtener de la base de datos tienen el formato HTML.Así que si estoy de mala suerte, por encima de la auxiliar va a despedazar mi artículo de la cadena de la derecha en el medio de una etiqueta html e insertar el "más..." de la cadena de allí (por ejemplo,entre ""), que se corrompe mi código html de la página.

¿Hay alguna forma de evitar esto o es que hay un plugin que me pueda usar para generar fragmentos/teasers de una cadena HTML?

¿Fue útil?

Solución 3

Muchas gracias por sus respuestas! Sin embargo, en el ínterin me topé con la jQuery HTML truncador Plugin , que se adapta perfectamente a mis propósitos y desplaza el truncamiento para el lado del cliente. No hay nada más fácil: -)

Otros consejos

Puede utilizar una combinación de Desinfección y Truncar .

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

Me estoy haciendo una tarea similar en el que tengo entradas de blog y sólo quiero mostrar un extracto rápido. Así que en mi opinión, lo hago simplemente:

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

que despoja a las etiquetas HTML, me da los primeros 150 caracteres y se maneja en la vista de lo que es MVC usar.

Buena suerte!

Mi respuesta aquí debe hacer el trabajo. La pregunta original (err, se le preguntó por mí) estaba a punto de truncar reducción del precio, pero terminó por convertir la reducción del precio a HTML entonces truncando que, por lo que debería funcionar.

Por supuesto, si su sitio se vuelve mucho tráfico, debería almacenar en caché el fragmento (tal vez cuando se creó el cargo / modificada, se puede almacenar el extracto en la base de datos?), Esto también significaría que podría permitir al usuario modificar o entrar en su propio extracto

Uso:

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

.. y el código (copiado de la otra respuesta):

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

tendría que escribir más complejos programas de análisis si no desea dividir en medio de los elementos HTML. tendría que recordar si se encuentra en medio de un bloque <> y si su entre dos etiquetas.

incluso si lo hizo, a pesar de ello tener problemas. si algunos ponen todo el artículo en un elemento HTML, ya que el analizador no podría dividirse en cualquier lugar, debido a la falta etiqueta de cierre.

si es posible en absoluto me gustaría tratar de no poner ninguna etiqueta en los artículos o mantenerlo a las etiquetas que No contiene nada (sin <div> y así sucesivamente). de esa manera usted sólo tiene que comprobar si se encuentra en medio de una etiqueta que es bastante simple:

  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

Me hubiera saneado el código HTML y extrae la primera frase. Asumiendo que tiene un modelo de artículo, con un atributo de 'cuerpo' que contiene el código 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

Esto convertiría a " es un importante artículo! Y aquí está el resto del artículo." en "Este es un artículo importante".

Lo resuelto utilizando la siguiente solución

Instalar la gema 'desinfectar'

gem install sanitize

y utiliza código siguiente, aquí cuerpo es el texto que contiene etiquetas html.

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

Da fragmento de código html válido.Espero que ayude a alguien.

En la actualidad existe una joya llamada HTMLTruncator que se encarga de esto para usted. Lo he utilizado para mostrar extractos de entradas y similares, y es muy robusto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top