Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
el-ckeditor / lib / el-ckeditor / el-ckeditor.rb
Size: Mime:
EUtils.register_extra_engines!

module EL
  module CKE
    def self.included base
      base.mount_controller base.const_set(:ELCKEController, Class.new(E) {
        include EUtils
        include EL::CKEHelpers
        self.const_set(:PARENT_CONTROLLER, base)

        map 'el-ckeditor-controller'
        engine :Slim
        view_prefix '/'
        view_fullpath File.expand_path('../templates', __FILE__)
        layout false

        before /browser/ do
          root = params[:root]  || halt(400, 'no root given')
          File.directory?(root) || halt(400, '"%s" should be a directory' % escape_html(root))
          @root = root.freeze
          @root_regexp = /\A#{Regexp.escape root}/.freeze
        end

        def editor
          snippets = normalize_snippets(opts[:snippets])
          snippets.any? && @snippets = "'%s'" % snippets.join("', '")
          @save_button = opts[:save_button] || self.class::SAVE_BUTTON_SELECTOR
          opts[:path] &&
            @browse_url = route(:browser, root: opts[:path], prefix: opts[:prefix])
          render
        end

        def browser
          render 'browser/layout'
        end

        def browser__tree path = nil
          template, context = path ? ['tree-leaf', {path: path}] : ['tree-root', {}]
          render 'browser/' + template, context
        end

        def browser__files
          render 'browser/files'
        end

        def browser__image
          if given_image = params[:image]
            image = File.expand_path(normalize_path(given_image).gsub(/\A\/+/, ''), @root)
            File.file?(image) || halt(400, '"%s" does not exists or is not a file' % escape_html(given_image))
            halt send_file(image)
          end
        end

        def browser__upload
          if given_path = params[:path]
            path = File.expand_path(normalize_path(given_path).gsub(/\A\/+/, ''), @root)
            File.directory?(path) || halt(400, '"%s" should be a directory' % escape_html(given_path))
            files = params[:files]
            files = [] unless files.is_a?(Array)
            files.each do |f|
              FileUtils.mv f[:tempfile], File.join(path, normalize_path(f[:filename]))
            end
            FileUtils.chmod_R(0755, path)
          end
        end

        def browser__delete
          if given_file = params[:file]
            file = File.expand_path(normalize_path(given_file).gsub(/\A\/+/, ''), @root)
            File.file?(file) || halt(400, '"%s" does not exists or is not a file' % escape_html(given_file))
            FileUtils.rm file
          end
        end

        def get_assets(*)
          env['PATH_INFO'] = env['PATH_INFO'].to_s.sub(self.class::ASSETS_REGEXP, '')
          send_files self.class::ASSETS_PATH
        end
      })

      base.class_exec do
        private
        # @param [String] editor_id
        # @param [String] content
        # @param [Hash]   opts
        # @option opts [Boolean] :readonly
        #
        # @option opts [Array] :snippets
        #
        # @option opts [String] :path
        #   path for file browser to load files from.
        #   should be relative to application root.
        #   if not given, file browser wont be activated.
        #
        # @option opts [String] :prefix
        #   a prefix to be prepended to files inserted by file browser.
        #
        # @option opts [String] :save_button
        #   a DOM selector for save button. by default .saveButton used.
        #   el-ckeditor will update the content of textarea when save button hovered.
        #   this could also be done by listening onchange event,
        #   but in this case the content will be duplicated
        #   and the page may become huge and slow on bigger documents.
        #   textarea are found by editor_id passed as first argument.
        #
        # @option opts [String]  :lang
        #
        def ckeditor editor_id, opts = {}
          fetch self.class::ELCKEController, :editor, params do |env|
            env.update EDITOR_ID: editor_id, EDITOR_OPTS: opts
          end
        end
      end
    end
  end
  CKEditor = CKE

  module CKEHelpers

    ASSETS_PATH = File.expand_path('../../../assets', __FILE__).freeze
    ASSETS_EXT  = '.el-cke'.freeze
    ASSETS_REGEXP = /#{Regexp.escape ASSETS_EXT}\Z/.freeze

    ckeditor_baseurl = Dir[ASSETS_PATH + '/ckeditor-*'].find do |e|
      File.directory?(e) && File.file?(File.join(e, '/ckeditor.js'))
    end
    CKEDITOR_BASEURL = File.basename(ckeditor_baseurl).freeze

    image_files = %w[.bmp .gif .jpg .jpeg .png .svg .ico .tif .tiff]
    IMAGE_FILES = (image_files.concat(image_files.map(&:upcase))).freeze

    video_files = %w[.flv .swf .mpg .mpeg .asf .wmv .mov .mp4 .m4v .avi]
    VIDEO_FILES = (video_files.concat(video_files.map(&:upcase)))

    SAVE_BUTTON_SELECTOR = '.saveButton'.freeze

    def shorten file, length = nil
      ext  = File.extname  file
      name = File.basename file, ext
      length ||= (name.scan(/[A-Z]/).size > 2 ? 8 : 10)
      name[0,length].strip << (name.size > length ? '..' : '') << ext
    end

    def managed_files dir
      Dir[File.join(dir.to_s, '*{%s}' % (IMAGE_FILES + VIDEO_FILES).join(','))]
    end

    # Array#include is slow enough, so building a Hash on first request
    # then using hash lookup which is a lot faster
    def image? file
      (@@image_files ||= Hash[IMAGE_FILES.zip(IMAGE_FILES)])[File.extname(file)]
    end

    def video? file
      (@@video_files ||= Hash[VIDEO_FILES.zip(VIDEO_FILES)])[File.extname(file)]
    end

    def browseable? file
      image?(file) || video?(file)
    end

    private
    def editor_id
      env[:EDITOR_ID] || raise(ArgumentError, 'No editor ID given')
    end

    def opts
      env[:EDITOR_OPTS] || {}
    end

    def parent_route(*args)
      self.class::PARENT_CONTROLLER.route(*args)
    end

    def normalize_snippets *snippets
      snippets = snippets[0].call if snippets[0].is_a?(Proc)
      snippets.compact.flatten.map {|s| s.to_s.gsub("'", '"')}.freeze
    end
  end
end