OpenProject is the leading open source project management software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openproject/config/initializers/redcloth_numbered_headings.rb

141 lines
3.6 KiB

#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'redcloth3'
module RedCloth3Patch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
alias_method_chain :block_textile_prefix, :numbering
end
end
module InstanceMethods
private
def block_textile_prefix_with_numbering(text)
text.replace(prepend_number_to_heading(text))
block_textile_prefix_without_numbering(text)
end
HEADING = /^h(\d)\.(.*)$/ unless defined? HEADING
NUMBERED_HEADING = /^h(\d)#\.(.*)$/ unless defined? NUMBERED_HEADING
def prepend_number_to_heading(text)
if text =~ NUMBERED_HEADING
level = $1.to_i
number = get_next_number_or_start_new_numbering level
new_text = "h#{level}. #{number}#{$2}"
elsif text =~ HEADING
reset_numbering
end
new_text.nil? ? text : new_text
end
def get_next_number_or_start_new_numbering(level)
begin
number = get_number_for_level level
rescue ArgumentError
reset_numbering
number = get_number_for_level level
end
number
end
def get_number_for_level(level)
@numbering_provider ||= Redcloth3::NumberingStack.new level
@numbering_provider.get_next_numbering_for_level level
end
def reset_numbering
@numbering_provider = nil
end
end
end
RedCloth3.send(:include, RedCloth3Patch)
module Redcloth3
class NumberingStack
def initialize(level)
@stack = []
@init_level = level ? level.to_i : 1
end
def get_next_numbering_for_level(level)
internal_level = map_external_to_internal_level level
increase_numbering_for_level internal_level
current_numbering
end
private
def increase_numbering_for_level(level)
if @stack[level].nil?
@stack[level] = 1
fill_nil_levels_with_zero
else
@stack[level] += 1
reset_higher_levels_than level
end
@stack[level]
end
def reset_higher_levels_than(level)
@stack = @stack.slice! 0, level + 1
end
def current_numbering
@stack.join('.') + '.'
end
def map_external_to_internal_level(level)
if level.to_i < @init_level
raise ArgumentError, 'Current level lower than initial level'
end
level.to_i - @init_level
end
def fill_nil_levels_with_zero
@stack.map! { |e| e.nil? ? 0 : e }
end
end
end