lib/delivery/resolvers/content_link_resolver.rb
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