Class: Deface::Override
Constant Summary
collapse
- @@_early =
[]
- @@actions =
[:remove, :replace, :replace_contents, :surround, :surround_contents, :insert_after, :insert_before, :insert_top, :insert_bottom, :set_attributes]
- @@sources =
[:text, :partial, :template]
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
#element_source, #load_template_source
Constructor Details
#initialize(args) ⇒ Override
Initializes new override, you must supply only one Target, Action & Source parameter for each override (and any number of Optional parameters).
Target
Action
-
:remove - Removes all elements that match the supplied selector
-
:replace - Replaces all elements that match the supplied selector
-
:replace_contents - Replaces the contents of all elements that match the supplied selector
-
:surround - Surrounds all elements that match the supplied selector, expects replacement markup to contain <%= render_original %> placeholder
-
:surround_contents - Surrounds the contents of all elements that match the supplied selector, expects replacement markup to contain <%= render_original %> placeholder
-
:insert_after - Inserts after all elements that match the supplied selector
-
:insert_before - Inserts before all elements that match the supplied selector
-
:insert_top - Inserts inside all elements that match the supplied selector, before all existing child
-
:insert_bottom - Inserts inside all elements that match the supplied selector, after all existing child
-
:set_attributes - Sets (or adds) attributes to all elements that match the supplied selector, expects :attributes option to be passed.
Source
-
:text - String containing markup
-
:partial - Relative path to partial
-
:template - Relative path to template
Optional
-
:name - Unique name for override so it can be identified and modified later. This needs to be unique within the same :virtual_path
-
:disabled - When set to true the override will not be applied.
-
:original - String containing original markup that is being overridden. If supplied Deface will log when the original markup changes, which helps highlight overrides that need attention when upgrading versions of the source application. Only really warranted for :replace overrides. NB: All whitespace is stripped before comparsion.
-
:closing_selector - A second css selector targeting an end element, allowing you to select a range of elements to apply an action against. The :closing_selector only supports the :replace, :remove and :replace_contents actions, and the end element must be a sibling of the first/starting element. Note the CSS general sibling selector (~) is used to match the first element after the opening selector.
-
:sequence - Used to order the application of an override for a specific virtual path, helpful when an override depends on another override being applied first. Supports: :sequence => n - where n is a positive or negative integer (lower numbers get applied first, default 100). :sequence => => “override_name” - where “override_name” is the name of an override defined for the
same virutal_path, the current override will be appplied before
the named override passed.
:sequence => => “override_name”) - the current override will be applied after the named override passed.
-
:attributes - A hash containing all the attributes to be set on the matched elements, eg: :attributes => {:class => “green”, :title => “some string”
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
# File 'lib/deface/override.rb', line 63
def initialize(args)
unless Rails.application.try(:config).respond_to?(:deface) and Rails.application.try(:config).deface.try(:overrides)
@@_early << args
warn "[WARNING] Deface railtie has not initialized yet, override '#{args[:name]}' is being declared too early."
return
end
raise(ArgumentError, ":name must be defined") unless args.key? :name
raise(ArgumentError, ":virtual_path must be defined") if args[:virtual_path].blank?
virtual_key = args[:virtual_path].to_sym
name_key = args[:name].to_s.parameterize
self.class.all[virtual_key] ||= {}
if self.class.all[virtual_key].has_key? name_key
@args = self.class.all[virtual_key][name_key].args
if (@@actions & args.keys).present?
@args.reject!{|key, value| (@@actions & @args.keys).include? key }
end
if (@@sources & args.keys).present?
@args.reject!{|key, value| (@@sources & @args.keys).include? key }
end
@args.merge!(args)
else
@args = args
raise(ArgumentError, ":action is invalid") if self.action.nil?
end
self.class.all[virtual_key][name_key] = self
end
|
Instance Attribute Details
#args ⇒ Object
Returns the value of attribute args.
6
7
8
|
# File 'lib/deface/override.rb', line 6
def args
@args
end
|
Class Method Details
.all ⇒ Object
348
349
350
|
# File 'lib/deface/override.rb', line 348
def self.all
Rails.application.config.deface.overrides.all
end
|
.apply(source, details, log = true) ⇒ Object
applies all applicable overrides to given source
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
|
# File 'lib/deface/override.rb', line 201
def self.apply(source, details, log=true)
overrides = find(details)
if log
log = defined?(Rails.logger)
end
if log && overrides.size > 0
Rails.logger.info "\e[1;32mDeface:\e[0m #{overrides.size} overrides found for '#{details[:virtual_path]}'"
end
unless overrides.empty?
doc = Deface::Parser.convert(source)
overrides.each do |override|
if override.disabled?
Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' is disabled") if log
next
end
if override.end_selector.blank?
matches = doc.css(override.selector)
if log
Rails.logger.send(matches.size == 0 ? :error : :info, "\e[1;32mDeface:\e[0m '#{override.name}' matched #{matches.size} times with '#{override.selector}'")
end
matches.each do |match|
override.validate_original(match)
case override.action
when :remove
match.replace ""
when :replace
match.replace override.source_element
when :replace_contents
match.children.remove
match.add_child(override.source_element)
when :surround, :surround_contents
new_source = override.source_element.clone(1)
if original = new_source.css("code:contains('render_original')").first
if override.action == :surround
original.replace match.clone(1)
match.replace new_source
elsif override.action == :surround_contents
original.replace match.children
match.children.remove
match.add_child new_source
end
else
end
when :insert_before
match.before override.source_element
when :insert_after
match.after override.source_element
when :insert_top
if match.children.size == 0
match.children = override.source_element
else
match.children.before(override.source_element)
end
when :insert_bottom
if match.children.size == 0
match.children = override.source_element
else
match.children.after(override.source_element)
end
when :set_attributes
override.attributes.each do |name, value|
match.set_attribute(name.to_s, value.to_s)
end
end
end
else
starting = doc.css(override.selector).first
if starting && starting.parent
ending = starting.parent.css(override.end_selector).first
else
ending = doc.css(override.end_selector).first
end
if starting && ending
if log
Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' matched starting with '#{override.selector}' and ending with '#{override.end_selector}'")
end
elements = select_range(starting, ending)
case override.action
when :remove
elements.map &:remove
when :replace
starting.before(override.source_element)
elements.map &:remove
when :replace_contents
elements[1..-2].map &:remove
starting.after(override.source_element)
end
else
if starting.nil?
Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' failed to match with starting selector '#{override.selector}'")
else
Rails.logger.info("\e[1;32mDeface:\e[0m '#{override.name}' failed to match with end selector '#{override.end_selector}'")
end
end
end
end
details[:updated_at] = Time.now
source = doc.to_s
Deface::Parser.undo_erb_markup!(source)
end
source
end
|
.find(details) ⇒ Object
finds all applicable overrides for supplied template
333
334
335
336
337
338
339
340
341
342
343
344
345
|
# File 'lib/deface/override.rb', line 333
def self.find(details)
return [] if self.all.empty? || details.empty?
virtual_path = details[:virtual_path]
return [] if virtual_path.nil?
virtual_path = virtual_path[1..-1] if virtual_path.first == '/'
result = []
result << self.all[virtual_path.to_sym].try(:values)
result.flatten.compact.sort_by &:sequence
end
|
Instance Method Details
#action ⇒ Object
149
150
151
|
# File 'lib/deface/override.rb', line 149
def action
(@@actions & @args.keys).first
end
|
#attributes ⇒ Object
195
196
197
|
# File 'lib/deface/override.rb', line 195
def attributes
@args[:attributes] || []
end
|
#disabled? ⇒ Boolean
186
187
188
|
# File 'lib/deface/override.rb', line 186
def disabled?
@args.key?(:disabled) ? @args[:disabled] : false
end
|
#end_selector ⇒ Object
190
191
192
193
|
# File 'lib/deface/override.rb', line 190
def end_selector
return nil if @args[:closing_selector].blank?
"#{self.selector} ~ #{@args[:closing_selector]}"
end
|
#name ⇒ Object
108
109
110
|
# File 'lib/deface/override.rb', line 108
def name
@args[:name]
end
|
#original_source ⇒ Object
167
168
169
170
171
|
# File 'lib/deface/override.rb', line 167
def original_source
return nil unless @args[:original].present?
Deface::Parser.convert(@args[:original].clone)
end
|
#selector ⇒ Object
104
105
106
|
# File 'lib/deface/override.rb', line 104
def selector
@args[self.action]
end
|
#sequence ⇒ Object
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
# File 'lib/deface/override.rb', line 112
def sequence
return 100 unless @args.key?(:sequence)
if @args[:sequence].is_a? Hash
key = @args[:virtual_path].to_sym
if @args[:sequence].key? :before
ref_name = @args[:sequence][:before]
if self.class.all[key].key? ref_name.to_s
return self.class.all[key][ref_name.to_s].sequence - 1
else
return 100
end
elsif @args[:sequence].key? :after
ref_name = @args[:sequence][:after]
if self.class.all[key].key? ref_name.to_s
return self.class.all[key][ref_name.to_s].sequence + 1
else
return 100
end
else
return 100
end
else
return @args[:sequence].to_i
end
rescue SystemStackError
if defined?(Rails)
Rails.logger.error "\e[1;32mDeface: [WARNING]\e[0m Circular sequence dependency includes override named: '#{self.name}' on '#{@args[:virtual_path]}'."
end
return 100
end
|
#source ⇒ Object
153
154
155
156
157
158
159
160
161
|
# File 'lib/deface/override.rb', line 153
def source
erb = if @args.key? :partial
load_template_source(@args[:partial], true)
elsif @args.key? :template
load_template_source(@args[:template], false)
elsif @args.key? :text
@args[:text]
end
end
|
#source_element ⇒ Object
163
164
165
|
# File 'lib/deface/override.rb', line 163
def source_element
Deface::Parser.convert(source.clone)
end
|
#validate_original(match) ⇒ Object
logs if original source has changed
174
175
176
177
178
179
180
181
182
183
184
|
# File 'lib/deface/override.rb', line 174
def validate_original(match)
return true if self.original_source.nil?
valid = self.original_source.to_s.gsub(/\s/, '') == match.to_s.gsub(/\s/, '')
if !valid && defined?(Rails.logger) == "constant"
Rails.logger.error "\e[1;32mDeface: [WARNING]\e[0m The original source for '#{self.name}' has changed, this override should be reviewed to ensure it's still valid."
end
valid
end
|