Class: HTMLProofer::Element

Inherits:
Object
  • Object
show all
Includes:
Utils
Defined in:
lib/html-proofer/element.rb

Overview

Represents the element currently being processed

Direct Known Subclasses

OpenGraphElement

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils

#create_nokogiri, #pluralize, #swap

Constructor Details

#initialize(obj, check, logger) ⇒ Element

Returns a new instance of Element.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/html-proofer/element.rb', line 13

def initialize(obj, check, logger)
  @logger = logger
  # Construct readable ivars for every element
  begin
    obj.attributes.each_pair do |attribute, value|
      name = attribute.tr('-:.;@', '_').to_s.to_sym
      (class << self; self; end).send(:attr_reader, name)
      instance_variable_set("@#{name}", value.value)
    end
  rescue NameError => e
    @logger.log :error, "Attribute set `#{obj}` contains an error!"
    raise e
  end

  @aria_hidden = defined?(@aria_hidden) && @aria_hidden == 'true'

  @data_proofer_ignore = defined?(@data_proofer_ignore)

  @text = obj.content
  @check = check
  @checked_paths = {}
  @type = check.class.name
  @line = obj.line

  @html = check.html

  parent_attributes = obj.ancestors.map { |a| a.respond_to?(:attributes) && a.attributes }
  parent_attributes.pop # remove document at the end
  @parent_ignorable = parent_attributes.any? { |a| !a['data-proofer-ignore'].nil? }

  # fix up missing protocols
  if defined?(@href)
    @href.insert(0, 'http:') if %r{^//}.match?(@href)
  else
    @href = nil
  end

  if defined?(@src)
    @src.insert(0, 'http:') if %r{^//}.match?(@src)
  else
    @src = nil
  end

  if defined?(@srcset)
    @srcset.insert(0, 'http:') if %r{^//}.match?(@srcset)
  else
    @srcset = nil
  end
end

Instance Attribute Details

#altObject (readonly)

Returns the value of attribute alt.



11
12
13
# File 'lib/html-proofer/element.rb', line 11

def alt
  @alt
end

#data_proofer_ignoreObject (readonly)

Returns the value of attribute data_proofer_ignore.



11
12
13
# File 'lib/html-proofer/element.rb', line 11

def data_proofer_ignore
  @data_proofer_ignore
end

#hrefObject (readonly)

Returns the value of attribute href.



11
12
13
# File 'lib/html-proofer/element.rb', line 11

def href
  @href
end

#idObject (readonly)

Returns the value of attribute id.



11
12
13
# File 'lib/html-proofer/element.rb', line 11

def id
  @id
end

#lineObject (readonly)

Returns the value of attribute line.



11
12
13
# File 'lib/html-proofer/element.rb', line 11

def line
  @line
end

Returns the value of attribute link.



11
12
13
# File 'lib/html-proofer/element.rb', line 11

def link
  @link
end

#nameObject (readonly)

Returns the value of attribute name.



11
12
13
# File 'lib/html-proofer/element.rb', line 11

def name
  @name
end

#srcObject (readonly)

Returns the value of attribute src.



11
12
13
# File 'lib/html-proofer/element.rb', line 11

def src
  @src
end

Instance Method Details

#absolute_pathObject



220
221
222
223
224
# File 'lib/html-proofer/element.rb', line 220

def absolute_path
  path = file_path || @check.path

  File.expand_path(path, Dir.pwd)
end

#absolute_path?(path) ⇒ Boolean

Returns:

  • (Boolean)


180
181
182
# File 'lib/html-proofer/element.rb', line 180

def absolute_path?(path)
  path.start_with?('/')
end

#allow_hash_href?Boolean

Returns:

  • (Boolean)


133
134
135
# File 'lib/html-proofer/element.rb', line 133

def allow_hash_href?
  @check.options[:allow_hash_href]
end

#allow_missing_href?Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/html-proofer/element.rb', line 129

def allow_missing_href?
  @check.options[:allow_missing_href]
end

#baseObject



249
250
251
# File 'lib/html-proofer/element.rb', line 249

def base
  @base ||= @html.at_css('base')
end

#check_img_http?Boolean

Returns:

  • (Boolean)


137
138
139
# File 'lib/html-proofer/element.rb', line 137

def check_img_http?
  @check.options[:check_img_http]
end

#check_sri?Boolean

Returns:

  • (Boolean)


141
142
143
# File 'lib/html-proofer/element.rb', line 141

def check_sri?
  @check.options[:check_sri]
end

#exists?Boolean

checks if a file exists relative to the current pwd

Returns:

  • (Boolean)


214
215
216
217
218
# File 'lib/html-proofer/element.rb', line 214

def exists?
  return @checked_paths[absolute_path] if @checked_paths.key?(absolute_path)

  @checked_paths[absolute_path] = File.exist?(absolute_path)
end

#external?Boolean

path is external to the file

Returns:

  • (Boolean)


150
151
152
# File 'lib/html-proofer/element.rb', line 150

def external?
  !internal?
end

#file_pathObject



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/html-proofer/element.rb', line 184

def file_path
  return if path.nil? || path.empty?

  path_dot_ext = ''

  path_dot_ext = path + @check.options[:extension] if @check.options[:assume_extension]

  base = if absolute_path?(path) # path relative to root
           # either overwrite with root_dir; or, if source is directory, use that; or, just get the current file's dirname
           @check.options[:root_dir] || (File.directory?(@check.src) ? @check.src : File.dirname(@check.src))
         elsif File.exist?(File.expand_path(path, @check.src)) || File.exist?(File.expand_path(path_dot_ext, @check.src)) # relative links, path is a file
           File.dirname(@check.path)
         elsif File.exist?(File.join(File.dirname(@check.path), path)) || File.exist?(File.join(File.dirname(@check.path), path_dot_ext)) # rubocop:disable Lint/DuplicateBranch; relative links in nested dir, path is a file
           File.dirname(@check.path)
         else # relative link, path is a directory
           @check.path
         end

  file = File.join(base, path)

  if @check.options[:assume_extension] && File.file?("#{file}#{@check.options[:extension]}")
    file = "#{file}#{@check.options[:extension]}"
  elsif File.directory?(file) && !unslashed_directory?(file) # implicit index support
    file = File.join file, @check.options[:directory_index_file]
  end

  file
end

#follow_location?Boolean

Returns:

  • (Boolean)


245
246
247
# File 'lib/html-proofer/element.rb', line 245

def follow_location?
  @check.options[:typhoeus] && @check.options[:typhoeus][:followlocation]
end

#hashObject



91
92
93
# File 'lib/html-proofer/element.rb', line 91

def hash
  parts&.fragment
end


172
173
174
# File 'lib/html-proofer/element.rb', line 172

def hash_link
  url.start_with?('#')
end

#htmlObject



253
254
255
256
257
258
259
260
261
262
263
# File 'lib/html-proofer/element.rb', line 253

def html
  # If link is on the same page, then URL is on the current page. use the same HTML as for current page
  if link_points_to_same_page?
    @html
  elsif internal?
    # link on another page, e.g. /about#Team - need to get HTML from the other page
    create_nokogiri(absolute_path)
  else
    raise NotImplementedError, 'HTMLProofer should not have gotten here. Please report this as a bug.'
  end
end

#ignore?Boolean

Returns:

  • (Boolean)


108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/html-proofer/element.rb', line 108

def ignore?
  return true if @data_proofer_ignore
  return true if @parent_ignorable

  return true if /^javascript:/.match?(url)

  # ignore base64 encoded images
  return true if %w[ImageCheck FaviconCheck].include?(@type) && /^data:image/.match?(url)

  # ignore user defined URLs
  return true if ignores_pattern_check(@check.options[:url_ignore])
end

#ignore_alt?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/html-proofer/element.rb', line 121

def ignore_alt?
  return true if ignores_pattern_check(@check.options[:alt_ignore]) || @aria_hidden
end

#ignore_empty_alt?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/html-proofer/element.rb', line 125

def ignore_empty_alt?
  @check.options[:empty_alt_ignore]
end

#ignore_empty_mailto?Boolean

Returns:

  • (Boolean)


145
146
147
# File 'lib/html-proofer/element.rb', line 145

def ignore_empty_mailto?
  @check.options[:ignore_empty_mailto]
end

#ignores_pattern_check(links) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/html-proofer/element.rb', line 226

def ignores_pattern_check(links)
  return false unless links.is_a?(Array)

  links.each do |ignore|
    case ignore
    when String
      return true if ignore == url
    when Regexp
      return true if ignore&.match?(url)
    end
  end

  false
end

#internal?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/html-proofer/element.rb', line 154

def internal?
  relative_link? || internal_absolute_link?
end

#internal_absolute_link?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/html-proofer/element.rb', line 158

def internal_absolute_link?
  url.start_with?('/')
end

Returns:

  • (Boolean)


168
169
170
# File 'lib/html-proofer/element.rb', line 168

def link_points_to_same_page?
  hash_link || param_link
end

#non_http_remote?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/html-proofer/element.rb', line 104

def non_http_remote?
  !scheme.nil? && !remote?
end


176
177
178
# File 'lib/html-proofer/element.rb', line 176

def param_link
  url.start_with?('?')
end

#partsObject



81
82
83
84
85
# File 'lib/html-proofer/element.rb', line 81

def parts
  @parts ||= Addressable::URI.parse url
rescue URI::Error, Addressable::URI::InvalidURIError
  @parts = nil
end

#pathObject



87
88
89
# File 'lib/html-proofer/element.rb', line 87

def path
  Addressable::URI.unencode parts.path unless parts.nil?
end

#path?Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/html-proofer/element.rb', line 77

def path?
  !parts.host.nil? && !parts.path.nil?
end

#relative_link?Boolean

Returns:

  • (Boolean)


162
163
164
165
166
# File 'lib/html-proofer/element.rb', line 162

def relative_link?
  return false if remote?

  hash_link || param_link || url.start_with?('.') || url =~ /^\S/
end

#remote?Boolean

path is to an external server

Returns:

  • (Boolean)


100
101
102
# File 'lib/html-proofer/element.rb', line 100

def remote?
  %w[http https].include? scheme
end

#schemeObject



95
96
97
# File 'lib/html-proofer/element.rb', line 95

def scheme
  parts&.scheme
end

#unslashed_directory?(file) ⇒ Boolean

Returns:

  • (Boolean)


241
242
243
# File 'lib/html-proofer/element.rb', line 241

def unslashed_directory?(file)
  File.directory?(file) && !file.end_with?(File::SEPARATOR) && !follow_location?
end

#urlObject



63
64
65
66
67
68
69
70
71
# File 'lib/html-proofer/element.rb', line 63

def url
  return @url if defined?(@url)

  @url = (@src || @srcset || @href || '').delete("\u200b").strip
  @url = Addressable::URI.join(base.attr('href') || '', url).to_s if base
  return @url if @check.options[:url_swap].empty?

  @url = swap(@url, @check.options[:url_swap])
end

#valid?Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/html-proofer/element.rb', line 73

def valid?
  !parts.nil?
end