示例#1
0
bool FixUrlFilter::filter(QList<HtmlToken> &tokens, int options) const
{
  Q_UNUSED(options)

  QList<HtmlToken> out;
  QString name;
  bool remove = false;

  foreach (const HtmlToken &token, tokens) {
    if (token.type == HtmlToken::StartTag && token.tag == LS("a")) {
      HtmlATag tag(token);
      if (tag.url.startsWith(LS("chat://channel/"))) {
        ClientChannel user = ChatUrls::channel(QUrl(tag.url));
        if (user)
          name = user->name();
      }

      out.append(token);
    }
    else if (!name.isEmpty()) {
      if (name != token.text) {
        out.append(HtmlToken(name));
        out.append(HtmlToken(HtmlToken::Tag, LS("</a>")));
        remove = true;

        if (token.text.startsWith(name))
          out.append(HtmlToken(LC(' ') + token.text.mid(name.size())));
        else
          out.append(LC(' ') + token.text);
      }
      else
        out.append(token);

      name.clear();
    }
    else if (token.type == HtmlToken::EndTag && token.tag == LS("a") && remove) {
      remove = false;
    }
    else
      out.append(token);
  }

  tokens = out;
  return true;
}
示例#2
0
void EmoticonsFilter::parse(QList<HtmlToken> &tokens, const QString &text, int pos) const
{
  if (text.isEmpty())
    return;

  if (pos == -1 || m_count > 6) {
    tokens.append(HtmlToken(text));
    return;
  }

  if (pos < text.size() - 1 && text.at(pos) == LC(' '))
    pos++;

  // Возможно в этой позиции находится начало смайла.
  if (m_emoticons->index().contains(text.at(pos))) {
    QString t = m_emoticons->find(text, pos);

    // Если текст не пустой, смайл найден.
    if (!t.isEmpty()) {

      // Смайл находится в конце строки.
      if (pos + t.size() == text.size()) {
        if (pos)
          tokens.append(HtmlToken(text.left(pos)));

        make(tokens, t);
        return;
      }
      // Смайл находится в внутри строки и содержит после себя пробел.
      else if (text.at(pos + t.size()) == LC(' ')) {
        if (pos)
          tokens.append(HtmlToken(text.left(pos)));

        make(tokens, t);
        parse(tokens, text.mid(pos + t.size()));
        return;
      }
    }
  }

  parse(tokens, text, text.indexOf(LC(' '), pos + 1));
}
示例#3
0
void EmoticonsFilter::make(QList<HtmlToken> &tokens, const QString &text) const
{
  Emoticon emoticon = m_emoticons->get(text);
  if (!emoticon) {
    tokens.append(HtmlToken(text));
    return;
  }

  m_count++;
  HtmlToken a(HtmlToken::Tag, HtmlATag(LS("emoticon:") + ChatId::toBase32(text.toUtf8()), text).toText());
  tokens.append(a);

  QString img = QString(LS("<img class=\"emoticon\" title=\"%1\" alt=\"%1\" src=\"%2\" width=\"%3\" height=\"%4\" />"))
      .arg(text)
      .arg(QUrl::fromLocalFile(emoticon->file()).toString())
      .arg(emoticon->width())
      .arg(emoticon->height());

  HtmlToken tag(img);
  tag.parent = LS("a");
  tokens.append(tag);
  tokens.append(a.toEndTag());
}
示例#4
0
/*!
 * Оптимизация и дополнительная фильтрация токенов.
 */
void HtmlFilter::optimize(QList<HtmlToken> &tokens) const
{
  int index = -1;
  for (int i = 0; i < tokens.size(); ++i) {
    if (!tokens.at(i).simple) {
      index = i;
      break;
    }
  }

  if (index == -1)
    return;

  HtmlToken token = tokens.at(index);

  if (token.tag == LS("a") || token.tag == LS("font")) {
    tokens[index].simple = true;
    int gt = endTag(token.tag, tokens, index);

    // Если закрывающий тег не найден, удаляем тег.
    if (gt == -1) {
      tokens.removeAt(index);
      return optimize(tokens);
    }

    // Если закрывающий следует сразу после открывающего, удаляем тег и закрывающий тег.
    if (gt - index == 1) {
      tokens.removeAt(index);
      if (index < tokens.size())
        tokens.removeAt(index);

      return optimize(tokens);
    }

    // Удаляем все не текстовые токены внутри тега.
    for (int i = gt - 1; i > index; --i) {
      if (tokens.at(i).type != HtmlToken::Text) {
        tokens.removeAt(i);
        gt--;
      }
      else {
        tokens[i].parent = token.tag;
      }
    }

    AbstractTag *tag = 0;
    if (token.tag == LS("a"))
      tag = new HtmlATag(token);
    else if (token.tag == LS("font"))
      tag = new HtmlFontTag(token);

    if (!tag->valid || gt - index == 1) {
      tokens.removeAt(gt);
      tokens.removeAt(index);
    }
    else
      tokens[index].text = tag->toText();

    delete tag;
    return optimize(tokens);
  }
  /// Тег span в зависимости от css стилей преобразуется в теги b, i, u, s и font
  /// и полностью удаляется из текста. Тег font используется для установки цвета элемента.
  else if (token.tag == LS("span")) {
    QList<HtmlToken> tags;
    const Range range = attrBody(LS("style"), token.text);

    if (range.first != -1) {
      QString value;

      if (cssValue(LS("font-weight"), token.text, range, value) && (value == LS("bold") || value == LS("bolder") || value == LS("600") || value == LS("700") || value == LS("800") || value == LS("900")))
        tags.append(HtmlToken(HtmlToken::Tag, LS("<b>")));

      if (cssValue(LS("font-style"), token.text, range, value) && value == LS("italic"))
        tags.append(HtmlToken(HtmlToken::Tag, LS("<i>")));

      if (cssValue(LS("text-decoration"), token.text, range, value)) {
        if (value == LS("underline"))
          tags.append(HtmlToken(HtmlToken::Tag, LS("<u>")));
        else if (value == LS("line-through"))
          tags.append(HtmlToken(HtmlToken::Tag, LS("<s>")));
      }

      if (cssValue(LS("color"), token.text, range, value) && colorValue(value)) {
        HtmlToken token(HtmlToken::Tag, LS("<font color=\"") + value + LS("\">"));
        token.simple = true;
        tags.append(token);
      }
    }

    tokens.removeAt(index);
    int gt = endTag(token.tag, tokens, index);

    if (gt == -1)
      return optimize(tokens);

    tokens.removeAt(gt);
    if (index == gt)
      return optimize(tokens);

    gt++;

    foreach (HtmlToken tag, tags) {
      tokens.insert(index, tag);
      tokens.insert(gt, tag.toEndTag());
      index++;
      gt++;
    }
示例#5
0
/*!
 * Поиск ссылок в тексте и автоматическое преобразование их в html ссылки.
 */
void LinksFilter::parse(QList<HtmlToken> &tokens, const QString &text) const
{
  int index = -1;
  int last = -1;
  QString url;

  /// - http/https/ftp полный список в \p m_scheme.
  for (int i = 0; i < m_scheme.size(); ++i) {
    index = text.indexOf(m_scheme.at(i));
    if (index != -1) {
      if (index > 0)
        tokens.append(HtmlToken(text.left(index)));

      url = this->url(text, index, last);
      makeUrl(tokens, url, url);

      if (last != -1)
        return parse(tokens, text.mid(last));

      return;
    }
  }


  /// - Ссылки вида www.exampe.com в преобразуются в http.
  index = text.indexOf(LS("www."));
  if (index != -1) {
    url = this->url(text, index, last);

    if (url.count(LC('.')) > 1) {
      if (index > 0)
        tokens.append(HtmlToken(text.left(index)));

      makeUrl(tokens, LS("http://") + url, url);

      if (last != -1)
        return parse(tokens, text.mid(last));

      return;
    }

    if (last != -1) {
      tokens.append(HtmlToken(text.left(last)));
      return parse(tokens, text.mid(last));
    }
  }

  /// - Ссылки вида [email protected] преобразуются в mailto.
  index = text.indexOf(LC('@'));
  if (index != -1) {
    int start = text.lastIndexOf(LC(' '), index);
    QString name = text.mid(start + 1, index - start - 1);
    last = -1;

    if (!name.isEmpty()) {
      url = this->url(text, index, last);
      if (url.contains(LC('.'))) {
        if (index > 0) {
          tokens.append(HtmlToken(text.left(index - name.size())));

          makeUrl(tokens, LS("mailto:") + name + url, name + url);

          if (last != -1)
            return parse(tokens, text.mid(last));

          return;
        }
      }
    }

    if (last != -1) {
      tokens.append(HtmlToken(text.left(last)));
      return parse(tokens, text.mid(last));
    }
  }

  tokens.append(HtmlToken(text));
}