Kentico/delivery-sdk-ruby

View on GitHub
lib/delivery/resolvers/content_link_resolver.rb

Summary

Maintainability
A
25 mins
Test Coverage
require 'nokogiri'

module Kontent
  module Ai
    module Delivery
      module Resolvers
        # Locates <a data-item-id=""> tags in content and calls a user-defined method
        # to supply the href for content item links.
        # See https://github.com/kontent-ai/delivery-sdk-ruby#resolving-links
        class ContentLinkResolver
          # Constructor.
          #
          # * *Args*:
          #   - *found_handler* (+lambda+) _optional_ Method to be called when resolving a content link and the content item is present in the response
          #   - *not_found_handler* (+lambda+) _optional_ Method to be called when resolving a content link and the content item isn't present in the response
          def initialize(found_handler = nil, not_found_handler = nil)
            @found_handler = found_handler
            @not_found = not_found_handler
          end

          # Resolves all links in the content.
          #
          # * *Args*:
          #   - *content* (+string+) The string value stored in the element
          #   - *links* (+Array+) The collection of links from an element's 'links' JSON node
          #
          # * *Returns*:
          #   - +string+ The original content passed, with all links resolved
          def resolve(content, links)
            doc = Nokogiri::HTML.parse(content).xpath('//body')
            links = links.map { |link| ContentLink.new link }
            tags = doc.xpath('//a[@data-item-id]')
            # This line performs the link resolving and replaces the tags in doc
            tags.map { |tag| resolve_tag tag, links }
            doc.to_xhtml
          end

          private

          # Accepts a tag found in the content and tries to locate matching
          # source link from JSON response. If found, resolves URL and returns
          # the tag with generated HREF.
          #
          # * *Args*:
          #   - *tag* (+string+) A <a data-item-id=""> tag found in the content
          #   - *links* (+Array+) The collection of links from an element's 'links' JSON node, converted to Kontent::Ai::Delivery::Resolvers::ContentLink objects
          #
          # * *Returns*:
          #   - +string+ The <a data-item-id=""> tag with an HREF generated by the +provide_url+ method
          def resolve_tag(tag, links)
            matches = links.select { |link| link.id == tag['data-item-id'].to_s }
            url = provide_url matches, tag['data-item-id']
            tag['href'] = url
            tag
          end

          # Uses the +resolve_link+ method to generate a URL for a ContentLink
          # object, or +resolve_404+ if the content item was not present in the
          # response.
          #
          # * *Args*:
          #   - *matches* (+Array+) The ContentLink objects with an ID matching a particular <a data-item-id=""> tag
          #   - *id* (+string+) The ID of the <a data-item-id=""> tag being resolved
          #
          # * *Returns*:
          #   - +string+ A url to the item or 404 page
          def provide_url(matches, id)
            if matches.empty?
              if @not_found_handler.nil?
                resolve_404 id
              else
                @not_found_handler.call id
              end
            else
              if @found_handler.nil?
                resolve_link matches[0]
              else
                @found_handler.call matches[0]
              end
            end
          end
        end

        # Model for links from the JSON response
        class ContentLink
          attr_accessor :code_name, :type, :url_slug, :id

          # Constructor.
          #
          # * *Args*:
          #   - *link* (+JSON+) One link from an element's 'links' JSON node
          def initialize(link)
            self.id = link[0]
            self.code_name = link[1]['codename']
            self.type = link[1]['type']
            self.url_slug = link[1]['url_slug']
          end
        end
      end
    end
  end
end