Chris@1517: # Redmine - project management software Chris@1517: # Copyright (C) 2006-2014 Jean-Philippe Lang Chris@1517: # Chris@1517: # This program is free software; you can redistribute it and/or Chris@1517: # modify it under the terms of the GNU General Public License Chris@1517: # as published by the Free Software Foundation; either version 2 Chris@1517: # of the License, or (at your option) any later version. Chris@1517: # Chris@1517: # This program is distributed in the hope that it will be useful, Chris@1517: # but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@1517: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@1517: # GNU General Public License for more details. Chris@1517: # Chris@1517: # You should have received a copy of the GNU General Public License Chris@1517: # along with this program; if not, write to the Free Software Chris@1517: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Chris@1517: Chris@1517: require 'cgi' Chris@1517: Chris@1517: module Redmine Chris@1517: module WikiFormatting Chris@1517: module Markdown Chris@1517: class HTML < Redcarpet::Render::HTML Chris@1517: include ActionView::Helpers::TagHelper Chris@1517: Chris@1517: def link(link, title, content) Chris@1517: css = nil Chris@1517: unless link && link.starts_with?('/') Chris@1517: css = 'external' Chris@1517: end Chris@1517: content_tag('a', content.to_s.html_safe, :href => link, :title => title, :class => css) Chris@1517: end Chris@1517: Chris@1517: def block_code(code, language) Chris@1517: if language.present? Chris@1517: "
" +
Chris@1517: Redmine::SyntaxHighlighting.highlight_by_language(code, language) +
Chris@1517: "
"
Chris@1517: else
Chris@1517: "" + CGI.escapeHTML(code) + "" Chris@1517: end Chris@1517: end Chris@1517: end Chris@1517: Chris@1517: class Formatter Chris@1517: def initialize(text) Chris@1517: @text = text Chris@1517: end Chris@1517: Chris@1517: def to_html(*args) Chris@1517: html = formatter.render(@text) Chris@1517: # restore wiki links eg. [[Foo]] Chris@1517: html.gsub!(%r{\[(.*?)\]}) do Chris@1517: "[[#{$2}]]" Chris@1517: end Chris@1517: # restore Redmine links with double-quotes, eg. version:"1.0" Chris@1517: html.gsub!(/(\w):"(.+?)"/) do Chris@1517: "#{$1}:\"#{$2}\"" Chris@1517: end Chris@1517: html Chris@1517: end Chris@1517: Chris@1517: def get_section(index) Chris@1517: section = extract_sections(index)[1] Chris@1517: hash = Digest::MD5.hexdigest(section) Chris@1517: return section, hash Chris@1517: end Chris@1517: Chris@1517: def update_section(index, update, hash=nil) Chris@1517: t = extract_sections(index) Chris@1517: if hash.present? && hash != Digest::MD5.hexdigest(t[1]) Chris@1517: raise Redmine::WikiFormatting::StaleSectionError Chris@1517: end Chris@1517: t[1] = update unless t[1].blank? Chris@1517: t.reject(&:blank?).join "\n\n" Chris@1517: end Chris@1517: Chris@1517: def extract_sections(index) Chris@1517: sections = ['', '', ''] Chris@1517: offset = 0 Chris@1517: i = 0 Chris@1517: l = 1 Chris@1517: inside_pre = false Chris@1517: @text.split(/(^(?:.+\r?\n\r?(?:\=+|\-+)|#+.+|~~~.*)\s*$)/).each do |part| Chris@1517: level = nil Chris@1517: if part =~ /\A~{3,}(\S+)?\s*$/ Chris@1517: if $1 Chris@1517: if !inside_pre Chris@1517: inside_pre = true Chris@1517: end Chris@1517: else Chris@1517: inside_pre = !inside_pre Chris@1517: end Chris@1517: elsif inside_pre Chris@1517: # nop Chris@1517: elsif part =~ /\A(#+).+/ Chris@1517: level = $1.size Chris@1517: elsif part =~ /\A.+\r?\n\r?(\=+|\-+)\s*$/ Chris@1517: level = $1.include?('=') ? 1 : 2 Chris@1517: end Chris@1517: if level Chris@1517: i += 1 Chris@1517: if offset == 0 && i == index Chris@1517: # entering the requested section Chris@1517: offset = 1 Chris@1517: l = level Chris@1517: elsif offset == 1 && i > index && level <= l Chris@1517: # leaving the requested section Chris@1517: offset = 2 Chris@1517: end Chris@1517: end Chris@1517: sections[offset] << part Chris@1517: end Chris@1517: sections.map(&:strip) Chris@1517: end Chris@1517: Chris@1517: private Chris@1517: Chris@1517: def formatter Chris@1517: @@formatter ||= Redcarpet::Markdown.new( Chris@1517: Redmine::WikiFormatting::Markdown::HTML.new( Chris@1517: :filter_html => true, Chris@1517: :hard_wrap => true Chris@1517: ), Chris@1517: :autolink => true, Chris@1517: :fenced_code_blocks => true, Chris@1517: :space_after_headers => true, Chris@1517: :tables => true, Chris@1517: :strikethrough => true, Chris@1517: :superscript => true, Chris@1517: :no_intra_emphasis => true Chris@1517: ) Chris@1517: end Chris@1517: end Chris@1517: end Chris@1517: end Chris@1517: end