Project

General

Profile

Defect #44358 » 0003b-Add-image-placeholder-mode-44358.patch

Florian Walchshofer, 2026-10-20 23:05

View differences:

config/configuration.yml.example
263 263
  # Larger output is truncated to this limit.
264 264
  # Default: 102400 (100 kilobytes)
265 265
  #markdownized_preview_max_output_size: 102400
266
  #
267
  # Controls how embedded images in Office document previews are handled.
268
  #
269
  # Available values:
270
  # render      - Extract embedded images and render them in the preview (default)
271
  # placeholder - Replace images with a markdown placeholder generated by the
272
  #               Pandoc Lua filter
273
  #
274
  #markdownized_preview_images: render
266 275

  
267 276
# specific configuration options for production environment
268 277
# that overrides the default ones
extra/pandoc_filter/markdownized_preview.lua
1
image_count = 0
2

  
3
function Image(el)
4
  image_count = image_count + 1
5

  
6
  local alt = pandoc.utils.stringify(el.caption)
7

  
8
  if alt == "" then
9
    local ext = el.src:match("%.([^.]+)$") or "img"
10
    alt = image_count .. "." .. ext
11
  end
12

  
13
  return pandoc.Str("[🖼️ " .. alt .. "] ")
14
end
lib/redmine/configuration.rb
32 32
      'thumbnails_generation_timeout' => 10,
33 33
      'markdownized_preview_generation_timeout' => 10,
34 34
      'markdownized_preview_max_source_size' => 10.megabytes,
35
      'markdownized_preview_max_output_size' => 100.kilobytes
35
      'markdownized_preview_max_output_size' => 100.kilobytes,
36
      'markdownized_preview_images' => 'render'
36 37
    }
37 38

  
38 39
    @config = nil
lib/redmine/markdownizer.rb
30 30
    PREVIEW_GENERATION_TIMEOUT = Redmine::Configuration['markdownized_preview_generation_timeout'].to_i
31 31
    MAX_SOURCE_SIZE = Redmine::Configuration['markdownized_preview_max_source_size'].to_i
32 32
    MAX_OUTPUT_SIZE = Redmine::Configuration['markdownized_preview_max_output_size'].to_i
33
    IMAGES_MODE = Redmine::Configuration['markdownized_preview_images'].to_s
34
    LUA_FILTER = Rails.root.join("extra", "pandoc_filter", "markdownized_preview.lua").freeze
33 35

  
34 36
    def self.supports?(filename)
35 37
      markdownizable_extensions.include?(File.extname(filename.to_s).downcase)
......
47 49
      directory = File.dirname(target)
48 50
      basedir = File.dirname(Attachment.markdownized_previews_storage_path)
49 51
      FileUtils.mkdir_p(directory)
50
      args = [COMMAND, source, "-t", "gfm", "--extract-media=markdownized_previews/#{attachment_id}/"]
52
      args = [COMMAND, source, "-t", "gfm"]
53

  
54
      if IMAGES_MODE == 'placeholder'
55
        args << "--lua-filter=#{LUA_FILTER}"
56
      else
57
        args << "--extract-media=markdownized_previews/#{attachment_id}/"
58
      end
59

  
51 60
      pid = nil
52 61
      output = Tempfile.new('markdownized-preview')
53 62

  
test/functional/attachments_controller_test.rb
453 453
    assert_select '.nodata', :count => 0
454 454
  end
455 455

  
456
  def test_show_msword_with_replaced_images
457
    skip unless Redmine::Markdownizer.available?
458

  
459
    old = Redmine::Markdownizer::IMAGES_MODE
460
    Redmine::Markdownizer.send(:remove_const, :IMAGES_MODE)
461
    Redmine::Markdownizer.const_set(:IMAGES_MODE, 'placeholder')
462

  
463
    begin
464
      set_tmp_attachments_directory
465

  
466
      a = Attachment.new(
467
        :container => Issue.find(1),
468
        :file => uploaded_test_file(
469
          'msword.docx',
470
          'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
471
        ),
472
        :author => User.find(1)
473
      )
474
      assert a.save
475

  
476
      get(:show, :params => {:id => a.id})
477

  
478
      assert_response :success
479
      assert_equal 'text/html', @response.media_type
480

  
481
      assert_select 'div.filecontent.wiki', :text => /Redmine is a flexible project management web application/
482
      assert_select 'div.filecontent.wiki img', 0
483
      assert_select 'div.filecontent.wiki', :text => /\[🖼️ 1\.png\]/
484
      children = Dir.children(a.markdownized_preview_directory)
485
      assert_equal ['preview.md'], children
486
    ensure
487
      Redmine::Markdownizer.send(:remove_const, :IMAGES_MODE)
488
      Redmine::Markdownizer.const_set(:IMAGES_MODE, old)
489
    end
490
  end
491

  
492
  def test_show_libreoffice_with_replaced_images
493
    skip unless Redmine::Markdownizer.available?
494

  
495
    old = Redmine::Markdownizer::IMAGES_MODE
496
    Redmine::Markdownizer.send(:remove_const, :IMAGES_MODE)
497
    Redmine::Markdownizer.const_set(:IMAGES_MODE, 'placeholder')
498

  
499
    begin
500
      set_tmp_attachments_directory
501
      a = Attachment.new(
502
        :container => Issue.find(1),
503
        :file => uploaded_test_file(
504
          'libreoffice-writer.odt',
505
          'application/vnd.oasis.opendocument.text'
506
        ),
507
        :author => User.find(1)
508
      )
509
      assert a.save
510

  
511
      get(:show, :params => {:id => a.id})
512

  
513
      assert_response :success
514
      assert_equal 'text/html', @response.media_type
515
      assert_select 'div.filecontent.wiki', :text => /Redmine is a flexible project management web application/
516
      assert_select 'div.filecontent.wiki img', 0
517
      assert_select 'div.filecontent.wiki', :text => /\[🖼️ 1\.png\]/
518
      children = Dir.children(a.markdownized_preview_directory)
519
      assert_equal ['preview.md'], children
520
    ensure
521
      Redmine::Markdownizer.send(:remove_const, :IMAGES_MODE)
522
      Redmine::Markdownizer.const_set(:IMAGES_MODE, old)
523
    end
524
  end
525

  
456 526
  def test_show_other_with_no_preview
457 527
    @request.session[:user_id] = 2
458 528
    get(:show, :params => {:id => 6})
(8-8/8)