Class: PostPresenter

Inherits:
BasePresenter show all
Includes:
Memery
Defined in:
app/presenters/post_presenter.rb

Overview

Presenter: post presenter.

Instance Attribute Summary

Attributes inherited from BasePresenter

#current_account, #options, #url_helper

Instance Method Summary collapse

Methods inherited from BasePresenter

#can?, #capture, #concat, #content_tag, #fa_icon, #h, #initialize, #link_to, #number_to_currency, #present, presents, #r, #safe_present, #simple_format, #u

Constructor Details

This class inherits a constructor from BasePresenter

Instance Method Details

#article_body(preview_mode: false) ⇒ Object



59
60
61
# File 'app/presenters/post_presenter.rb', line 59

def article_body(preview_mode: false)
  localized_solution_with_toc(preview_mode: preview_mode).body
end

#article_body_descObject



73
74
75
# File 'app/presenters/post_presenter.rb', line 73

def article_body_desc
  h.truncate(post&.description || stripped_article_body, length: 300)
end

#article_published_atObject



167
168
169
170
# File 'app/presenters/post_presenter.rb', line 167

def 
  # Must be DateTime YYYY-MM-DDThh:mm:ssTZD
  r.effective_published_date&.to_datetime
end

#article_published_at_formattedObject



172
173
174
175
176
# File 'app/presenters/post_presenter.rb', line 172

def 
  return unless 

  .strftime('%B %-d, %Y')
end

#article_revised_atObject



178
179
180
# File 'app/presenters/post_presenter.rb', line 178

def article_revised_at
  r.revised_at&.to_datetime
end

#article_revised_at_formattedObject



182
183
184
185
186
# File 'app/presenters/post_presenter.rb', line 182

def article_revised_at_formatted
  return unless article_revised_at

  article_revised_at.strftime('%B %-d, %Y')
end

#article_sectionObject



205
206
207
208
# File 'app/presenters/post_presenter.rb', line 205

def article_section
  # Return the first keyword or first tag, or 'Uncategorized'
  r.meta_keywords&.split(',')&.first&.strip.presence || r.tags&.first.presence || 'Uncategorized'
end

#article_tagsObject



198
199
200
201
202
203
# File 'app/presenters/post_presenter.rb', line 198

def 
  keywords = r.meta_keywords&.split(',')&.map(&:strip)
  keywords = r.tags if keywords.blank?
  # Exclude internal "for-*-page" tags which are used for page content placement
  (keywords || []).reject { |t| t.to_s.start_with?('for-') }
end

#article_toc(preview_mode: false) ⇒ Object



55
56
57
# File 'app/presenters/post_presenter.rb', line 55

def article_toc(preview_mode: false)
  localized_solution_with_toc(preview_mode: preview_mode).toc
end

#author_nameObject



114
115
116
117
118
# File 'app/presenters/post_presenter.rb', line 114

def author_name
  return 'https://www.facebook.com/WarmlyYours/' unless r.author&.full_name

  r.author&.full_name
end

#author_twitterObject



160
161
162
163
164
165
# File 'app/presenters/post_presenter.rb', line 160

def author_twitter
  '@WarmlyYours'
  # Later when this is defined we can use an employee twitter handle, today this does not exist
  # unless r.author&.twitter_handle
  # r.author&.twitter_handle
end


17
18
19
20
21
22
23
24
25
26
27
28
# File 'app/presenters/post_presenter.rb', line 17

def breadcrumbs_hash
  bc_array = [{ name: 'Radiant Journal', url: h.cms_link('/posts') }]
  custom_breadcrumbs = r.breadcrumbs_hash.dup
  if custom_breadcrumbs.blank? && (main_tag = r.main_public_tag)
    # make a breadcrumb out of it
    tag_title, tag = Post.category_tags_for_select.find { |to| to[1] == main_tag }
    bc_array << { name: tag_title, url: h.cms_link("/posts/#{tag}/tag") } if tag_title && tag
  else
    bc_array.concat(custom_breadcrumbs)
  end
  bc_array
end

#cache_keyObject



9
10
11
# File 'app/presenters/post_presenter.rb', line 9

def cache_key
  "#{I18n.locale}/#{post.cache_key}"
end


77
78
79
# File 'app/presenters/post_presenter.rb', line 77

def canonical_link
  h.cms_link(h.post_url(r), strip_params: true)
end

#get_imageObject



49
50
51
52
53
# File 'app/presenters/post_presenter.rb', line 49

def get_image
  return unless r.preview_image

  h.og_image_asset_url(r.preview_image)
end

#get_keywordsObject



13
14
15
# File 'app/presenters/post_presenter.rb', line 13

def get_keywords
  r.meta_keywords.presence || r.tags&.join(', ')
end

#localized_solution_with_toc(preview_mode: false) ⇒ Object



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'app/presenters/post_presenter.rb', line 210

def localized_solution_with_toc(preview_mode: false)
  s = OpenStruct.new(body: localized_solution(nil, preview_mode: preview_mode), toc: nil, body_html_doc: nil)
  return s unless r.has_toc

  # Parse toc headers and embed an anchor in them
  doc = localized_solution_html_doc(preview_mode: preview_mode)
  toc_headers = doc.css(toc_selector.presence || 'h2')
  toc = {}
  toc_headers.each do |element|
    next unless (title = element.text.strip.presence)

    element_anchor = element.text.parameterize
    toc[title] = element_anchor
    h.(:a, title, name: element_anchor)
    element['id'] = element_anchor
  end
  s.body_html_doc = doc
  s.body = doc.at('body')&.inner_html.presence&.html_safe
  s.toc = h.render(partial: '/posts/toc', locals: { toc: toc })
  s
end

#meta_description(max_length: 160) ⇒ Object



133
134
135
136
137
138
139
# File 'app/presenters/post_presenter.rb', line 133

def meta_description(max_length: 160)
  description = r.meta_description.presence
  description ||= r.description.presence
  description ||= r.subject.presence
  h.truncate(description, length: max_length, separator: ' ')
  # description << " (#{Country.country_name_from_locale})" if description && I18n.locale.to_s != 'en-US'
end

#meta_keywordsObject



141
142
143
# File 'app/presenters/post_presenter.rb', line 141

def meta_keywords
  r.meta_keywords.presence || r.tags&.join(', ').presence
end

#post_comments_sizeObject



106
107
108
# File 'app/presenters/post_presenter.rb', line 106

def post_comments_size
  r.post_comments.size
end

#preview_image_presenterObject



43
44
45
46
47
# File 'app/presenters/post_presenter.rb', line 43

def preview_image_presenter
  return unless r.preview_image

  h.present(r.preview_image, Www::ImagePresenter)
end

#publish_labelObject



188
189
190
191
192
193
194
195
196
# File 'app/presenters/post_presenter.rb', line 188

def publish_label
  return unless 

  if article_revised_at && article_revised_at > 
    "Updated on #{article_revised_at_formatted}"
  else
    "Published on #{}"
  end
end


30
31
32
33
34
35
36
37
38
39
40
41
# File 'app/presenters/post_presenter.rb', line 30

def quick_links_hash
  ql_array = breadcrumbs_hash.dup
  if breadcrumbs_hash.any? { |h| h[:url].match?(/floor|indoor-heating/) }
    ql_array << { name: 'Instant Quote', url: h.cms_link('/floor-heating/quote-builder') }
    ql_array << { name: 'Running Costs', url: h.cms_link('/floor-heating/cost-calculator') }
  end
  if breadcrumbs_hash.any? { |h| h[:url].match?(%r{/snow-melting|outdoor-heating}) }
    ql_array << { name: 'Instant Quote', url: h.cms_link('/snow-melting/quote-builder') }
    ql_array << { name: 'Running Costs', url: h.cms_link('/snow-melting/cost-calculator') }
  end
  ql_array.uniq { |h| h[:url] }.sort_by { |h| h[:name] }
end

#reading_time_in_minutesObject



69
70
71
# File 'app/presenters/post_presenter.rb', line 69

def reading_time_in_minutes
  (stripped_article_body.to_s.split.size / 200.0).ceil
end

#render_body(preview_mode: false) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'app/presenters/post_presenter.rb', line 81

def render_body(preview_mode: false)
  locale = I18n.locale
  body = Liquid::ParseEnvironment.parse(article_body(preview_mode: preview_mode).to_s).render(
    'preview_mode' => preview_mode,
    'locale' => locale.to_s,
    'canada' => %i[en-CA fr-CA].include?(locale),
    'usa' => locale == :'en-US'
  )
  return body if preview_mode

  # HtmlContentSanitizer now runs on save (via auto_sanitize_html checkbox)
  Seo::ImageOptimizer.new.process(body).html_out
end

#render_descriptionObject



95
96
97
98
99
100
101
102
103
104
# File 'app/presenters/post_presenter.rb', line 95

def render_description
  return if r.description.blank?

  locale = I18n.locale
  Liquid::ParseEnvironment.parse(r.description.to_s).render(
    'locale' => locale.to_s,
    'canada' => %i[en-CA fr-CA].include?(locale),
    'usa' => locale == :'en-US'
  ).html_safe
end

#schema_dot_org_structureObject



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'app/presenters/post_presenter.rb', line 233

def schema_dot_org_structure
  wc = word_count.to_i
  schema = SchemaDotOrg::BlogPosting.new(
    identifier: id.to_s,
    headline: subject,
    name: subject,
    description: meta_description,
    articleBody: stripped_article_body,
    keywords: ,
    wordcount: wc.positive? ? wc.to_s : nil,
    inLanguage: I18n.locale.to_s.tr('_', '-'),
    datePublished: r.effective_published_date,
    dateModified: r.effective_revised_date,
    dateCreated: created_at,
    articleSection: article_section,
    mainEntityOfPage: canon_link,
    url: canon_link,
    author: build_author_schema,
    publisher: build_publisher_schema,
    image: build_image_schema,
    comment: build_comment_graph
  )
  schema.id_iri = canon_link
  schema
end

#stripped_article_bodyObject



63
64
65
66
67
# File 'app/presenters/post_presenter.rb', line 63

def stripped_article_body
  parsed_body = Liquid::ParseEnvironment.parse(article_body.to_s)
  stripped_body = h.strip_tags(parsed_body.render)
  stripped_body&.tr('"', '')
end

#to_json_ldObject



259
260
261
# File 'app/presenters/post_presenter.rb', line 259

def to_json_ld
  schema_dot_org_structure.to_s
end

#user_imageObject



120
121
122
123
124
# File 'app/presenters/post_presenter.rb', line 120

def user_image
  return unless r.author&.email

  "https://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(r.author&.email&.presence)}.jpg"
end

#user_image_tagObject



126
127
128
129
130
131
# File 'app/presenters/post_presenter.rb', line 126

def user_image_tag
  img_url = user_image_url(size: '90x90>')
  return unless img_url

  h.image_tag(img_url, alt: r.author&.full_name, class: 'img-fluid', width: 90, height: 90)
end

#user_image_url(size: '90x90>') ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'app/presenters/post_presenter.rb', line 145

def user_image_url(size: '90x90>')
  return unless r.author

  if (pp = r.author&.profile_image)
    pp.image_url(size: size)
  elsif (email = r.author&.email&.presence)
    # Gravatar
    require 'digest/md5'
    hash = Digest::MD5.hexdigest(email.downcase)
    "https://www.gravatar.com/avatar/#{hash}.jpg"
  else
    nil
  end
end

#word_countObject



110
111
112
# File 'app/presenters/post_presenter.rb', line 110

def word_count
  r.localized_solution&.presence&.scan(/\w+/)&.size
end